diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index ea806a510..baf53b8f0 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -185,6 +185,12 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r return getObjectNInfo(ctx, bucket, object, rs, r.Header, readLock, ObjectOptions{}) } + objInfo, err := getObjectInfo(ctx, bucket, object, opts) + if err != nil { + writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) + return + } + if err = s3Select.Open(getObject); err != nil { if serr, ok := err.(s3select.SelectError); ok { w.WriteHeader(serr.HTTPStatusCode()) @@ -198,12 +204,6 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r s3Select.Evaluate(w) s3Select.Close() - objInfo, err := getObjectInfo(ctx, bucket, object, opts) - if err != nil { - logger.LogIf(ctx, err) - return - } - // Get host and port from Request.RemoteAddr. host, port, err := net.SplitHostPort(handlers.GetSourceIP(r)) if err != nil { diff --git a/docs/select/README.md b/docs/select/README.md index 1b8946dde..48d020ab7 100644 --- a/docs/select/README.md +++ b/docs/select/README.md @@ -3,6 +3,15 @@ Traditional retrieval of objects is always as whole entities, i.e GetObject for > This implementation is compatible with AWS S3 Select API +### Implemention status: + +- Full S3 SQL syntax is supported +- All aggregation, conditional, type-conversion and strings SQL functions are supported +- JSONPath expressions are not yet evaluated +- Large numbers (more than 64-bit) are not yet supported +- Date related functions are not yet supported (EXTRACT, DATE_DIFF, etc) +- S3's reserved keywords list is not yet respected + ## 1. Prerequisites - Install Minio Server from [here](http://docs.minio.io/docs/minio-quickstart-guide). - Familiarity with AWS S3 API diff --git a/pkg/s3select/csv/record.go b/pkg/s3select/csv/record.go index f58d48aa0..47ee818d0 100644 --- a/pkg/s3select/csv/record.go +++ b/pkg/s3select/csv/record.go @@ -32,7 +32,11 @@ type Record struct { nameIndexMap map[string]int64 } -// Get - gets the value for a column name. +// Get - gets the value for a column name. CSV fields do not have any +// defined type (other than the default string). So this function +// always returns fields using sql.FromBytes so that the type +// specified/implied by the query can be used, or can be automatically +// converted based on the query. func (r *Record) Get(name string) (*sql.Value, error) { index, found := r.nameIndexMap[name] if !found { @@ -40,11 +44,12 @@ func (r *Record) Get(name string) (*sql.Value, error) { } if index >= int64(len(r.csvRecord)) { - // No value found for column 'name', hence return empty string for compatibility. - return sql.NewString(""), nil + // No value found for column 'name', hence return null + // value + return sql.FromNull(), nil } - return sql.NewString(r.csvRecord[index]), nil + return sql.FromBytes([]byte(r.csvRecord[index])), nil } // Set - sets the value for a column name. diff --git a/pkg/s3select/json/record.go b/pkg/s3select/json/record.go index b05f27e69..d3003ee56 100644 --- a/pkg/s3select/json/record.go +++ b/pkg/s3select/json/record.go @@ -37,15 +37,15 @@ func (r *Record) Get(name string) (*sql.Value, error) { result := gjson.GetBytes(r.data, name) switch result.Type { case gjson.Null: - return sql.NewNull(), nil + return sql.FromNull(), nil case gjson.False: - return sql.NewBool(false), nil + return sql.FromBool(false), nil case gjson.Number: - return sql.NewFloat(result.Float()), nil + return sql.FromFloat(result.Float()), nil case gjson.String: - return sql.NewString(result.String()), nil + return sql.FromString(result.String()), nil case gjson.True: - return sql.NewBool(true), nil + return sql.FromBool(true), nil } return nil, fmt.Errorf("unsupported gjson value %v; %v", result, result.Type) @@ -54,19 +54,20 @@ func (r *Record) Get(name string) (*sql.Value, error) { // Set - sets the value for a column name. func (r *Record) Set(name string, value *sql.Value) (err error) { var v interface{} - switch value.Type() { - case sql.Null: - v = value.NullValue() - case sql.Bool: - v = value.BoolValue() - case sql.Int: - v = value.IntValue() - case sql.Float: - v = value.FloatValue() - case sql.String: - v = value.StringValue() - default: - return fmt.Errorf("unsupported sql value %v and type %v", value, value.Type()) + if b, ok := value.ToBool(); ok { + v = b + } else if f, ok := value.ToFloat(); ok { + v = f + } else if i, ok := value.ToInt(); ok { + v = i + } else if s, ok := value.ToString(); ok { + v = s + } else if value.IsNull() { + v = nil + } else if b, ok := value.ToBytes(); ok { + v = string(b) + } else { + return fmt.Errorf("unsupported sql value %v and type %v", value, value.GetTypeString()) } name = strings.Replace(name, "*", "__ALL__", -1) diff --git a/pkg/s3select/parquet/reader.go b/pkg/s3select/parquet/reader.go index 23c5daec0..70c0195cb 100644 --- a/pkg/s3select/parquet/reader.go +++ b/pkg/s3select/parquet/reader.go @@ -32,7 +32,7 @@ type Reader struct { } // Read - reads single record. -func (r *Reader) Read() (sql.Record, error) { +func (r *Reader) Read() (rec sql.Record, rerr error) { parquetRecord, err := r.file.Read() if err != nil { if err != io.EOF { @@ -43,39 +43,41 @@ func (r *Reader) Read() (sql.Record, error) { } record := json.NewRecord() - for name, v := range parquetRecord { + f := func(name string, v parquetgo.Value) bool { if v.Value == nil { - if err = record.Set(name, sql.NewNull()); err != nil { - return nil, errParquetParsingError(err) + if err := record.Set(name, sql.FromNull()); err != nil { + rerr = errParquetParsingError(err) } - - continue + return rerr == nil } var value *sql.Value switch v.Type { case parquetgen.Type_BOOLEAN: - value = sql.NewBool(v.Value.(bool)) + value = sql.FromBool(v.Value.(bool)) case parquetgen.Type_INT32: - value = sql.NewInt(int64(v.Value.(int32))) + value = sql.FromInt(int64(v.Value.(int32))) case parquetgen.Type_INT64: - value = sql.NewInt(v.Value.(int64)) + value = sql.FromInt(int64(v.Value.(int64))) case parquetgen.Type_FLOAT: - value = sql.NewFloat(float64(v.Value.(float32))) + value = sql.FromFloat(float64(v.Value.(float32))) case parquetgen.Type_DOUBLE: - value = sql.NewFloat(v.Value.(float64)) + value = sql.FromFloat(v.Value.(float64)) case parquetgen.Type_INT96, parquetgen.Type_BYTE_ARRAY, parquetgen.Type_FIXED_LEN_BYTE_ARRAY: - value = sql.NewString(string(v.Value.([]byte))) + value = sql.FromString(string(v.Value.([]byte))) default: - return nil, errParquetParsingError(nil) + rerr = errParquetParsingError(nil) + return false } if err = record.Set(name, value); err != nil { - return nil, errParquetParsingError(err) + rerr = errParquetParsingError(err) } + return rerr == nil } - return record, nil + parquetRecord.Range(f) + return record, rerr } // Close - closes underlaying readers. diff --git a/pkg/s3select/select.go b/pkg/s3select/select.go index 98b1ac40e..e267f823f 100644 --- a/pkg/s3select/select.go +++ b/pkg/s3select/select.go @@ -105,7 +105,7 @@ func (input *InputSerialization) UnmarshalXML(d *xml.Decoder, start xml.StartEle found++ } if !parsedInput.ParquetArgs.IsEmpty() { - if parsedInput.CompressionType != noneType { + if parsedInput.CompressionType != "" && parsedInput.CompressionType != noneType { return errInvalidRequestParameter(fmt.Errorf("CompressionType must be NONE for Parquet format")) } @@ -178,7 +178,7 @@ type S3Select struct { Output OutputSerialization `xml:"OutputSerialization"` Progress RequestProgress `xml:"RequestProgress"` - statement *sql.Select + statement *sql.SelectStatement progressReader *progressReader recordReader recordReader } @@ -209,12 +209,12 @@ func (s3Select *S3Select) UnmarshalXML(d *xml.Decoder, start xml.StartElement) e return errMissingRequiredParameter(fmt.Errorf("OutputSerialization must be provided")) } - statement, err := sql.NewSelect(parsedS3Select.Expression) + statement, err := sql.ParseSelectStatement(parsedS3Select.Expression) if err != nil { return err } - parsedS3Select.statement = statement + parsedS3Select.statement = &statement *s3Select = S3Select(parsedS3Select) return nil @@ -334,6 +334,14 @@ func (s3Select *S3Select) Evaluate(w http.ResponseWriter) { } for { + if s3Select.statement.LimitReached() { + if err = writer.SendStats(s3Select.getProgress()); err != nil { + // FIXME: log this error. + err = nil + } + break + } + if inputRecord, err = s3Select.recordReader.Read(); err != nil { if err != io.EOF { break @@ -358,19 +366,25 @@ func (s3Select *S3Select) Evaluate(w http.ResponseWriter) { break } - outputRecord = s3Select.outputRecord() - if outputRecord, err = s3Select.statement.Eval(inputRecord, outputRecord); err != nil { - break - } + if s3Select.statement.IsAggregated() { + if err = s3Select.statement.AggregateRow(inputRecord); err != nil { + break + } + } else { + outputRecord = s3Select.outputRecord() + if outputRecord, err = s3Select.statement.Eval(inputRecord, outputRecord); err != nil { + break + } - if !s3Select.statement.IsAggregated() { if !sendRecord() { break } + } } if err != nil { + fmt.Printf("SQL Err: %#v\n", err) if serr := writer.SendError("InternalError", err.Error()); serr != nil { // FIXME: log errors. } diff --git a/pkg/s3select/sql/aggregation.go b/pkg/s3select/sql/aggregation.go new file mode 100644 index 000000000..fd0669bad --- /dev/null +++ b/pkg/s3select/sql/aggregation.go @@ -0,0 +1,318 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "fmt" +) + +// Aggregation Function name constants +const ( + aggFnAvg FuncName = "AVG" + aggFnCount FuncName = "COUNT" + aggFnMax FuncName = "MAX" + aggFnMin FuncName = "MIN" + aggFnSum FuncName = "SUM" +) + +var ( + errNonNumericArg = func(fnStr FuncName) error { + return fmt.Errorf("%s() requires a numeric argument", fnStr) + } + errInvalidAggregation = errors.New("Invalid aggregation seen") +) + +type aggVal struct { + runningSum *Value + runningCount int64 + runningMax, runningMin *Value + + // Stores if at least one record has been seen + seen bool +} + +func newAggVal(fn FuncName) *aggVal { + switch fn { + case aggFnAvg, aggFnSum: + return &aggVal{runningSum: FromInt(0)} + case aggFnMin: + return &aggVal{runningMin: FromInt(0)} + case aggFnMax: + return &aggVal{runningMax: FromInt(0)} + default: + return &aggVal{} + } +} + +// evalAggregationNode - performs partial computation using the +// current row and stores the result. +// +// On success, it returns (nil, nil). +func (e *FuncExpr) evalAggregationNode(r Record) error { + // It is assumed that this function is called only when + // `e` is an aggregation function. + + var val *Value + var err error + funcName := e.getFunctionName() + if aggFnCount == funcName { + if e.Count.StarArg { + // Handle COUNT(*) + e.aggregate.runningCount++ + return nil + } + + val, err = e.Count.ExprArg.evalNode(r) + if err != nil { + return err + } + } else { + // Evaluate the (only) argument + val, err = e.SFunc.ArgsList[0].evalNode(r) + if err != nil { + return err + } + } + + if val.IsNull() { + // E.g. the column or field does not exist in the + // record - in all such cases the aggregation is not + // updated. + return nil + } + + argVal := val + if funcName != aggFnCount { + // All aggregation functions, except COUNT require a + // numeric argument. + + // Here, we diverge from Amazon S3 behavior by + // inferring untyped values are numbers. + if i, ok := argVal.bytesToInt(); ok { + argVal.setInt(i) + } else if f, ok := argVal.bytesToFloat(); ok { + argVal.setFloat(f) + } else { + return errNonNumericArg(funcName) + } + } + + // Mark that we have seen one non-null value. + isFirstRow := false + if !e.aggregate.seen { + e.aggregate.seen = true + isFirstRow = true + } + + switch funcName { + case aggFnCount: + // For all non-null values, the count is incremented. + e.aggregate.runningCount++ + + case aggFnAvg: + e.aggregate.runningCount++ + err = e.aggregate.runningSum.arithOp(opPlus, argVal) + + case aggFnMin: + err = e.aggregate.runningMin.minmax(argVal, false, isFirstRow) + + case aggFnMax: + err = e.aggregate.runningMax.minmax(argVal, true, isFirstRow) + + case aggFnSum: + err = e.aggregate.runningSum.arithOp(opPlus, argVal) + + default: + err = errInvalidAggregation + } + + return err +} + +func (e *AliasedExpression) aggregateRow(r Record) error { + return e.Expression.aggregateRow(r) +} + +func (e *Expression) aggregateRow(r Record) error { + for _, ex := range e.And { + err := ex.aggregateRow(r) + if err != nil { + return err + } + } + return nil +} + +func (e *AndCondition) aggregateRow(r Record) error { + for _, ex := range e.Condition { + err := ex.aggregateRow(r) + if err != nil { + return err + } + } + return nil +} + +func (e *Condition) aggregateRow(r Record) error { + if e.Operand != nil { + return e.Operand.aggregateRow(r) + } + return e.Not.aggregateRow(r) +} + +func (e *ConditionOperand) aggregateRow(r Record) error { + err := e.Operand.aggregateRow(r) + if err != nil { + return err + } + + if e.ConditionRHS == nil { + return nil + } + + switch { + case e.ConditionRHS.Compare != nil: + return e.ConditionRHS.Compare.Operand.aggregateRow(r) + case e.ConditionRHS.Between != nil: + err = e.ConditionRHS.Between.Start.aggregateRow(r) + if err != nil { + return err + } + return e.ConditionRHS.Between.End.aggregateRow(r) + case e.ConditionRHS.In != nil: + for _, elt := range e.ConditionRHS.In.Expressions { + err = elt.aggregateRow(r) + if err != nil { + return err + } + } + return nil + case e.ConditionRHS.Like != nil: + err = e.ConditionRHS.Like.Pattern.aggregateRow(r) + if err != nil { + return err + } + return e.ConditionRHS.Like.EscapeChar.aggregateRow(r) + default: + return errInvalidASTNode + } +} + +func (e *Operand) aggregateRow(r Record) error { + err := e.Left.aggregateRow(r) + if err != nil { + return err + } + for _, rt := range e.Right { + err = rt.Right.aggregateRow(r) + if err != nil { + return err + } + } + return nil +} + +func (e *MultOp) aggregateRow(r Record) error { + err := e.Left.aggregateRow(r) + if err != nil { + return err + } + for _, rt := range e.Right { + err = rt.Right.aggregateRow(r) + if err != nil { + return err + } + } + return nil +} + +func (e *UnaryTerm) aggregateRow(r Record) error { + if e.Negated != nil { + return e.Negated.Term.aggregateRow(r) + } + return e.Primary.aggregateRow(r) +} + +func (e *PrimaryTerm) aggregateRow(r Record) error { + switch { + case e.SubExpression != nil: + return e.SubExpression.aggregateRow(r) + case e.FuncCall != nil: + return e.FuncCall.aggregateRow(r) + } + return nil +} + +func (e *FuncExpr) aggregateRow(r Record) error { + switch e.getFunctionName() { + case aggFnAvg, aggFnSum, aggFnMax, aggFnMin, aggFnCount: + return e.evalAggregationNode(r) + default: + // TODO: traverse arguments and call aggregateRow on + // them if they could be an ancestor of an + // aggregation. + } + return nil +} + +// getAggregate() implementation for each AST node follows. This is +// called after calling aggregateRow() on each input row, to calculate +// the final aggregate result. + +func (e *Expression) getAggregate() (*Value, error) { + return e.evalNode(nil) +} + +func (e *FuncExpr) getAggregate() (*Value, error) { + switch e.getFunctionName() { + case aggFnCount: + return FromFloat(float64(e.aggregate.runningCount)), nil + + case aggFnAvg: + if e.aggregate.runningCount == 0 { + // No rows were seen by AVG. + return FromNull(), nil + } + err := e.aggregate.runningSum.arithOp(opDivide, FromInt(e.aggregate.runningCount)) + return e.aggregate.runningSum, err + + case aggFnMin: + if !e.aggregate.seen { + // No rows were seen by MIN + return FromNull(), nil + } + return e.aggregate.runningMin, nil + + case aggFnMax: + if !e.aggregate.seen { + // No rows were seen by MAX + return FromNull(), nil + } + return e.aggregate.runningMax, nil + + case aggFnSum: + // TODO: check if returning 0 when no rows were seen + // by SUM is expected behavior. + return e.aggregate.runningSum, nil + + default: + // TODO: + } + + return nil, errInvalidAggregation +} diff --git a/pkg/s3select/sql/analysis.go b/pkg/s3select/sql/analysis.go new file mode 100644 index 000000000..56c227b27 --- /dev/null +++ b/pkg/s3select/sql/analysis.go @@ -0,0 +1,290 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "fmt" +) + +// Query analysis - The query is analyzed to determine if it involves +// aggregation. +// +// Aggregation functions - An expression that involves aggregation of +// rows in some manner. Requires all input rows to be processed, +// before a result is returned. +// +// Row function - An expression that depends on a value in the +// row. They have an output for each input row. +// +// Some types of a queries are not valid. For example, an aggregation +// function combined with a row function is meaningless ("AVG(s.Age) + +// s.Salary"). Analysis determines if such a scenario exists so an +// error can be returned. + +var ( + // Fatal error for query processing. + errNestedAggregation = errors.New("Cannot nest aggregations") + errFunctionNotImplemented = errors.New("Function is not yet implemented") + errUnexpectedInvalidNode = errors.New("Unexpected node value") + errInvalidKeypath = errors.New("A provided keypath is invalid") +) + +// qProp contains analysis info about an SQL term. +type qProp struct { + isAggregation, isRowFunc bool + + err error +} + +// `combine` combines a pair of `qProp`s, so that errors are +// propagated correctly, and checks that an aggregation is not being +// combined with a row-function term. +func (p *qProp) combine(q qProp) { + switch { + case p.err != nil: + // Do nothing + case q.err != nil: + p.err = q.err + default: + p.isAggregation = p.isAggregation || q.isAggregation + p.isRowFunc = p.isRowFunc || q.isRowFunc + if p.isAggregation && p.isRowFunc { + p.err = errNestedAggregation + } + } +} + +func (e *SelectExpression) analyze(s *Select) (result qProp) { + if e.All { + return qProp{isRowFunc: true} + } + + for _, ex := range e.Expressions { + result.combine(ex.analyze(s)) + } + return +} + +func (e *AliasedExpression) analyze(s *Select) qProp { + return e.Expression.analyze(s) +} + +func (e *Expression) analyze(s *Select) (result qProp) { + for _, ac := range e.And { + result.combine(ac.analyze(s)) + } + return +} + +func (e *AndCondition) analyze(s *Select) (result qProp) { + for _, ac := range e.Condition { + result.combine(ac.analyze(s)) + } + return +} + +func (e *Condition) analyze(s *Select) (result qProp) { + if e.Operand != nil { + result = e.Operand.analyze(s) + } else { + result = e.Not.analyze(s) + } + return +} + +func (e *ConditionOperand) analyze(s *Select) (result qProp) { + if e.ConditionRHS == nil { + result = e.Operand.analyze(s) + } else { + result.combine(e.Operand.analyze(s)) + result.combine(e.ConditionRHS.analyze(s)) + } + return +} + +func (e *ConditionRHS) analyze(s *Select) (result qProp) { + switch { + case e.Compare != nil: + result = e.Compare.Operand.analyze(s) + case e.Between != nil: + result.combine(e.Between.Start.analyze(s)) + result.combine(e.Between.End.analyze(s)) + case e.In != nil: + for _, elt := range e.In.Expressions { + result.combine(elt.analyze(s)) + } + case e.Like != nil: + result.combine(e.Like.Pattern.analyze(s)) + if e.Like.EscapeChar != nil { + result.combine(e.Like.EscapeChar.analyze(s)) + } + default: + result = qProp{err: errUnexpectedInvalidNode} + } + return +} + +func (e *Operand) analyze(s *Select) (result qProp) { + result.combine(e.Left.analyze(s)) + for _, r := range e.Right { + result.combine(r.Right.analyze(s)) + } + return +} + +func (e *MultOp) analyze(s *Select) (result qProp) { + result.combine(e.Left.analyze(s)) + for _, r := range e.Right { + result.combine(r.Right.analyze(s)) + } + return +} + +func (e *UnaryTerm) analyze(s *Select) (result qProp) { + if e.Negated != nil { + result = e.Negated.Term.analyze(s) + } else { + result = e.Primary.analyze(s) + } + return +} + +func (e *PrimaryTerm) analyze(s *Select) (result qProp) { + switch { + case e.Value != nil: + result = qProp{} + + case e.JPathExpr != nil: + // Check if the path expression is valid + if len(e.JPathExpr.PathExpr) > 0 { + if e.JPathExpr.BaseKey.String() != s.From.As { + result = qProp{err: errInvalidKeypath} + return + } + } + result = qProp{isRowFunc: true} + + case e.SubExpression != nil: + result = e.SubExpression.analyze(s) + + case e.FuncCall != nil: + result = e.FuncCall.analyze(s) + + default: + result = qProp{err: errUnexpectedInvalidNode} + } + return +} + +func (e *FuncExpr) analyze(s *Select) (result qProp) { + funcName := e.getFunctionName() + + switch funcName { + case sqlFnCast: + return e.Cast.Expr.analyze(s) + + case sqlFnExtract: + return e.Extract.From.analyze(s) + + // Handle aggregation function calls + case aggFnAvg, aggFnMax, aggFnMin, aggFnSum, aggFnCount: + // Initialize accumulator + e.aggregate = newAggVal(funcName) + + var exprA qProp + if funcName == aggFnCount { + if e.Count.StarArg { + return qProp{isAggregation: true} + } + + exprA = e.Count.ExprArg.analyze(s) + } else { + if len(e.SFunc.ArgsList) != 1 { + return qProp{err: fmt.Errorf("%s takes exactly one argument", funcName)} + } + exprA = e.SFunc.ArgsList[0].analyze(s) + } + + if exprA.err != nil { + return exprA + } + if exprA.isAggregation { + return qProp{err: errNestedAggregation} + } + return qProp{isAggregation: true} + + case sqlFnCoalesce: + if len(e.SFunc.ArgsList) == 0 { + return qProp{err: fmt.Errorf("%s needs at least one argument", string(funcName))} + } + for _, arg := range e.SFunc.ArgsList { + result.combine(arg.analyze(s)) + } + return result + + case sqlFnNullIf: + if len(e.SFunc.ArgsList) != 2 { + return qProp{err: fmt.Errorf("%s needs exactly 2 arguments", string(funcName))} + } + for _, arg := range e.SFunc.ArgsList { + result.combine(arg.analyze(s)) + } + return result + + case sqlFnCharLength, sqlFnCharacterLength: + if len(e.SFunc.ArgsList) != 1 { + return qProp{err: fmt.Errorf("%s needs exactly 2 arguments", string(funcName))} + } + for _, arg := range e.SFunc.ArgsList { + result.combine(arg.analyze(s)) + } + return result + + case sqlFnLower, sqlFnUpper: + if len(e.SFunc.ArgsList) != 1 { + return qProp{err: fmt.Errorf("%s needs exactly 2 arguments", string(funcName))} + } + for _, arg := range e.SFunc.ArgsList { + result.combine(arg.analyze(s)) + } + return result + + case sqlFnSubstring: + errVal := fmt.Errorf("Invalid argument(s) to %s", string(funcName)) + result.combine(e.Substring.Expr.analyze(s)) + switch { + case e.Substring.From != nil: + result.combine(e.Substring.From.analyze(s)) + if e.Substring.For != nil { + result.combine(e.Substring.Expr.analyze(s)) + } + case e.Substring.Arg2 != nil: + result.combine(e.Substring.Arg2.analyze(s)) + if e.Substring.Arg3 != nil { + result.combine(e.Substring.Arg3.analyze(s)) + } + default: + result.err = errVal + } + return result + + } + + // TODO: implement other functions + return qProp{err: errFunctionNotImplemented} +} diff --git a/pkg/s3select/sql/arithexpr.go b/pkg/s3select/sql/arithexpr.go deleted file mode 100644 index e611ba54c..000000000 --- a/pkg/s3select/sql/arithexpr.go +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import "fmt" - -// ArithOperator - arithmetic operator. -type ArithOperator string - -const ( - // Add operator '+'. - Add ArithOperator = "+" - - // Subtract operator '-'. - Subtract ArithOperator = "-" - - // Multiply operator '*'. - Multiply ArithOperator = "*" - - // Divide operator '/'. - Divide ArithOperator = "/" - - // Modulo operator '%'. - Modulo ArithOperator = "%" -) - -// arithExpr - arithmetic function. -type arithExpr struct { - left Expr - right Expr - operator ArithOperator - funcType Type -} - -// String - returns string representation of this function. -func (f *arithExpr) String() string { - return fmt.Sprintf("(%v %v %v)", f.left, f.operator, f.right) -} - -func (f *arithExpr) compute(lv, rv *Value) (*Value, error) { - leftValueType := lv.Type() - rightValueType := rv.Type() - if !leftValueType.isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValueType) - return nil, errExternalEvalException(err) - } - if !rightValueType.isNumber() { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValueType) - return nil, errExternalEvalException(err) - } - - leftValue := lv.FloatValue() - rightValue := rv.FloatValue() - - var result float64 - switch f.operator { - case Add: - result = leftValue + rightValue - case Subtract: - result = leftValue - rightValue - case Multiply: - result = leftValue * rightValue - case Divide: - result = leftValue / rightValue - case Modulo: - result = float64(int64(leftValue) % int64(rightValue)) - } - - if leftValueType == Float || rightValueType == Float { - return NewFloat(result), nil - } - - return NewInt(int64(result)), nil -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *arithExpr) Eval(record Record) (*Value, error) { - leftValue, err := f.left.Eval(record) - if err != nil { - return nil, err - } - - rightValue, err := f.right.Eval(record) - if err != nil { - return nil, err - } - - if f.funcType == aggregateFunction { - return nil, nil - } - - return f.compute(leftValue, rightValue) -} - -// AggregateValue - returns aggregated value. -func (f *arithExpr) AggregateValue() (*Value, error) { - if f.funcType != aggregateFunction { - err := fmt.Errorf("%v is not aggreate expression", f) - return nil, errExternalEvalException(err) - } - - lv, err := f.left.AggregateValue() - if err != nil { - return nil, err - } - - rv, err := f.right.AggregateValue() - if err != nil { - return nil, err - } - - return f.compute(lv, rv) -} - -// Type - returns arithmeticFunction or aggregateFunction type. -func (f *arithExpr) Type() Type { - return f.funcType -} - -// ReturnType - returns Float as return type. -func (f *arithExpr) ReturnType() Type { - return Float -} - -// newArithExpr - creates new arithmetic function. -func newArithExpr(operator ArithOperator, left, right Expr) (*arithExpr, error) { - if !left.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v, not number", operator, left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - if !right.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: right side expression %v evaluate to %v; not number", operator, right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - funcType := arithmeticFunction - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - - switch right.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for aggregate evaluation", operator, right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &arithExpr{ - left: left, - right: right, - operator: operator, - funcType: funcType, - }, nil -} diff --git a/pkg/s3select/sql/compexpr.go b/pkg/s3select/sql/compexpr.go deleted file mode 100644 index 113894f02..000000000 --- a/pkg/s3select/sql/compexpr.go +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import ( - "fmt" - "regexp" - "strings" -) - -// ComparisonOperator - comparison operator. -type ComparisonOperator string - -const ( - // Equal operator '='. - Equal ComparisonOperator = "=" - - // NotEqual operator '!=' or '<>'. - NotEqual ComparisonOperator = "!=" - - // LessThan operator '<'. - LessThan ComparisonOperator = "<" - - // GreaterThan operator '>'. - GreaterThan ComparisonOperator = ">" - - // LessThanEqual operator '<='. - LessThanEqual ComparisonOperator = "<=" - - // GreaterThanEqual operator '>='. - GreaterThanEqual ComparisonOperator = ">=" - - // Between operator 'BETWEEN' - Between ComparisonOperator = "between" - - // In operator 'IN' - In ComparisonOperator = "in" - - // Like operator 'LIKE' - Like ComparisonOperator = "like" - - // NotBetween operator 'NOT BETWEEN' - NotBetween ComparisonOperator = "not between" - - // NotIn operator 'NOT IN' - NotIn ComparisonOperator = "not in" - - // NotLike operator 'NOT LIKE' - NotLike ComparisonOperator = "not like" - - // IsNull operator 'IS NULL' - IsNull ComparisonOperator = "is null" - - // IsNotNull operator 'IS NOT NULL' - IsNotNull ComparisonOperator = "is not null" -) - -// String - returns string representation of this operator. -func (operator ComparisonOperator) String() string { - return strings.ToUpper((string(operator))) -} - -func equal(leftValue, rightValue *Value) (bool, error) { - switch { - case leftValue.Type() == Null && rightValue.Type() == Null: - return true, nil - case leftValue.Type() == Bool && rightValue.Type() == Bool: - return leftValue.BoolValue() == rightValue.BoolValue(), nil - case (leftValue.Type() == Int || leftValue.Type() == Float) && - (rightValue.Type() == Int || rightValue.Type() == Float): - return leftValue.FloatValue() == rightValue.FloatValue(), nil - case leftValue.Type() == String && rightValue.Type() == String: - return leftValue.StringValue() == rightValue.StringValue(), nil - case leftValue.Type() == Timestamp && rightValue.Type() == Timestamp: - return leftValue.TimeValue() == rightValue.TimeValue(), nil - } - - return false, fmt.Errorf("left value type %v and right value type %v are incompatible for equality check", leftValue.Type(), rightValue.Type()) -} - -// comparisonExpr - comparison function. -type comparisonExpr struct { - left Expr - right Expr - to Expr - operator ComparisonOperator - funcType Type -} - -// String - returns string representation of this function. -func (f *comparisonExpr) String() string { - switch f.operator { - case Equal, NotEqual, LessThan, GreaterThan, LessThanEqual, GreaterThanEqual, In, Like, NotIn, NotLike: - return fmt.Sprintf("(%v %v %v)", f.left, f.operator, f.right) - case Between, NotBetween: - return fmt.Sprintf("(%v %v %v AND %v)", f.left, f.operator, f.right, f.to) - } - - return fmt.Sprintf("(%v %v %v %v)", f.left, f.right, f.to, f.operator) -} - -func (f *comparisonExpr) equal(leftValue, rightValue *Value) (*Value, error) { - result, err := equal(leftValue, rightValue) - if err != nil { - err = fmt.Errorf("%v: %v", f, err) - return nil, errExternalEvalException(err) - } - - return NewBool(result), nil -} - -func (f *comparisonExpr) notEqual(leftValue, rightValue *Value) (*Value, error) { - result, err := equal(leftValue, rightValue) - if err != nil { - err = fmt.Errorf("%v: %v", f, err) - return nil, errExternalEvalException(err) - } - - return NewBool(!result), nil -} - -func (f *comparisonExpr) lessThan(leftValue, rightValue *Value) (*Value, error) { - if !leftValue.Type().isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - if !rightValue.Type().isNumber() { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(leftValue.FloatValue() < rightValue.FloatValue()), nil -} - -func (f *comparisonExpr) greaterThan(leftValue, rightValue *Value) (*Value, error) { - if !leftValue.Type().isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - if !rightValue.Type().isNumber() { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(leftValue.FloatValue() > rightValue.FloatValue()), nil -} - -func (f *comparisonExpr) lessThanEqual(leftValue, rightValue *Value) (*Value, error) { - if !leftValue.Type().isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - if !rightValue.Type().isNumber() { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(leftValue.FloatValue() <= rightValue.FloatValue()), nil -} - -func (f *comparisonExpr) greaterThanEqual(leftValue, rightValue *Value) (*Value, error) { - if !leftValue.Type().isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - if !rightValue.Type().isNumber() { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(leftValue.FloatValue() >= rightValue.FloatValue()), nil -} - -func (f *comparisonExpr) computeBetween(leftValue, fromValue, toValue *Value) (bool, error) { - if !leftValue.Type().isNumber() { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValue.Type()) - return false, errExternalEvalException(err) - } - if !fromValue.Type().isNumber() { - err := fmt.Errorf("%v: from side expression evaluated to %v; not to number", f, fromValue.Type()) - return false, errExternalEvalException(err) - } - if !toValue.Type().isNumber() { - err := fmt.Errorf("%v: to side expression evaluated to %v; not to number", f, toValue.Type()) - return false, errExternalEvalException(err) - } - - return leftValue.FloatValue() >= fromValue.FloatValue() && - leftValue.FloatValue() <= toValue.FloatValue(), nil -} - -func (f *comparisonExpr) between(leftValue, fromValue, toValue *Value) (*Value, error) { - result, err := f.computeBetween(leftValue, fromValue, toValue) - if err != nil { - return nil, err - } - - return NewBool(result), nil -} - -func (f *comparisonExpr) notBetween(leftValue, fromValue, toValue *Value) (*Value, error) { - result, err := f.computeBetween(leftValue, fromValue, toValue) - if err != nil { - return nil, err - } - - return NewBool(!result), nil -} - -func (f *comparisonExpr) computeIn(leftValue, rightValue *Value) (found bool, err error) { - if rightValue.Type() != Array { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to Array", f, rightValue.Type()) - return false, errExternalEvalException(err) - } - - values := rightValue.ArrayValue() - - for i := range values { - found, err = equal(leftValue, values[i]) - if err != nil { - return false, err - } - - if found { - return true, nil - } - } - - return false, nil -} - -func (f *comparisonExpr) in(leftValue, rightValue *Value) (*Value, error) { - result, err := f.computeIn(leftValue, rightValue) - if err != nil { - err = fmt.Errorf("%v: %v", f, err) - return nil, errExternalEvalException(err) - } - - return NewBool(result), nil -} - -func (f *comparisonExpr) notIn(leftValue, rightValue *Value) (*Value, error) { - result, err := f.computeIn(leftValue, rightValue) - if err != nil { - err = fmt.Errorf("%v: %v", f, err) - return nil, errExternalEvalException(err) - } - - return NewBool(!result), nil -} - -func (f *comparisonExpr) computeLike(leftValue, rightValue *Value) (matched bool, err error) { - if leftValue.Type() != String { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to string", f, leftValue.Type()) - return false, errExternalEvalException(err) - } - if rightValue.Type() != String { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to string", f, rightValue.Type()) - return false, errExternalEvalException(err) - } - - matched, err = regexp.MatchString(rightValue.StringValue(), leftValue.StringValue()) - if err != nil { - err = fmt.Errorf("%v: %v", f, err) - return false, errExternalEvalException(err) - } - - return matched, nil -} - -func (f *comparisonExpr) like(leftValue, rightValue *Value) (*Value, error) { - result, err := f.computeLike(leftValue, rightValue) - if err != nil { - return nil, err - } - - return NewBool(result), nil -} - -func (f *comparisonExpr) notLike(leftValue, rightValue *Value) (*Value, error) { - result, err := f.computeLike(leftValue, rightValue) - if err != nil { - return nil, err - } - - return NewBool(!result), nil -} - -func (f *comparisonExpr) compute(leftValue, rightValue, toValue *Value) (*Value, error) { - switch f.operator { - case Equal: - return f.equal(leftValue, rightValue) - case NotEqual: - return f.notEqual(leftValue, rightValue) - case LessThan: - return f.lessThan(leftValue, rightValue) - case GreaterThan: - return f.greaterThan(leftValue, rightValue) - case LessThanEqual: - return f.lessThanEqual(leftValue, rightValue) - case GreaterThanEqual: - return f.greaterThanEqual(leftValue, rightValue) - case Between: - return f.between(leftValue, rightValue, toValue) - case In: - return f.in(leftValue, rightValue) - case Like: - return f.like(leftValue, rightValue) - case NotBetween: - return f.notBetween(leftValue, rightValue, toValue) - case NotIn: - return f.notIn(leftValue, rightValue) - case NotLike: - return f.notLike(leftValue, rightValue) - } - - panic(fmt.Errorf("unexpected expression %v", f)) -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *comparisonExpr) Eval(record Record) (*Value, error) { - leftValue, err := f.left.Eval(record) - if err != nil { - return nil, err - } - - rightValue, err := f.right.Eval(record) - if err != nil { - return nil, err - } - - var toValue *Value - if f.to != nil { - toValue, err = f.to.Eval(record) - if err != nil { - return nil, err - } - } - - if f.funcType == aggregateFunction { - return nil, nil - } - - return f.compute(leftValue, rightValue, toValue) -} - -// AggregateValue - returns aggregated value. -func (f *comparisonExpr) AggregateValue() (*Value, error) { - if f.funcType != aggregateFunction { - err := fmt.Errorf("%v is not aggreate expression", f) - return nil, errExternalEvalException(err) - } - - leftValue, err := f.left.AggregateValue() - if err != nil { - return nil, err - } - - rightValue, err := f.right.AggregateValue() - if err != nil { - return nil, err - } - - var toValue *Value - if f.to != nil { - toValue, err = f.to.AggregateValue() - if err != nil { - return nil, err - } - } - - return f.compute(leftValue, rightValue, toValue) -} - -// Type - returns comparisonFunction or aggregateFunction type. -func (f *comparisonExpr) Type() Type { - return f.funcType -} - -// ReturnType - returns Bool as return type. -func (f *comparisonExpr) ReturnType() Type { - return Bool -} - -// newComparisonExpr - creates new comparison function. -func newComparisonExpr(operator ComparisonOperator, funcs ...Expr) (*comparisonExpr, error) { - funcType := comparisonFunction - switch operator { - case Equal, NotEqual: - if len(funcs) != 2 { - panic(fmt.Sprintf("exactly two arguments are expected, but found %v", len(funcs))) - } - - left := funcs[0] - if !left.ReturnType().isBaseKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v is incompatible for equality check", operator, left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - right := funcs[1] - if !right.ReturnType().isBaseKind() { - err := fmt.Errorf("operator %v: right side expression %v evaluate to %v is incompatible for equality check", operator, right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case column, Array, function, arithmeticFunction, comparisonFunction, logicalFunction, record: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for equality check", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - switch right.Type() { - case column, Array, function, arithmeticFunction, comparisonFunction, logicalFunction, record: - err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for equality check", operator, right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &comparisonExpr{ - left: left, - right: right, - operator: operator, - funcType: funcType, - }, nil - - case LessThan, GreaterThan, LessThanEqual, GreaterThanEqual: - if len(funcs) != 2 { - panic(fmt.Sprintf("exactly two arguments are expected, but found %v", len(funcs))) - } - - left := funcs[0] - if !left.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v, not number", operator, left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - right := funcs[1] - if !right.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: right side expression %v evaluate to %v; not number", operator, right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - - switch right.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for aggregate evaluation", operator, right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &comparisonExpr{ - left: left, - right: right, - operator: operator, - funcType: funcType, - }, nil - - case In, NotIn: - if len(funcs) != 2 { - panic(fmt.Sprintf("exactly two arguments are expected, but found %v", len(funcs))) - } - - left := funcs[0] - if !left.ReturnType().isBaseKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v is incompatible for equality check", operator, left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - right := funcs[1] - if right.ReturnType() != Array { - err := fmt.Errorf("operator %v: right side expression %v evaluate to %v is incompatible for equality check", operator, right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case column, Array, function, arithmeticFunction, comparisonFunction, logicalFunction, record: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - switch right.Type() { - case Array, aggregateFunction: - default: - err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for aggregate evaluation", operator, right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &comparisonExpr{ - left: left, - right: right, - operator: operator, - funcType: funcType, - }, nil - - case Like, NotLike: - if len(funcs) != 2 { - panic(fmt.Sprintf("exactly two arguments are expected, but found %v", len(funcs))) - } - - left := funcs[0] - if !left.ReturnType().isStringKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v, not string", operator, left, left.ReturnType()) - return nil, errLikeInvalidInputs(err) - } - - right := funcs[1] - if !right.ReturnType().isStringKind() { - err := fmt.Errorf("operator %v: right side expression %v evaluate to %v, not string", operator, right, right.ReturnType()) - return nil, errLikeInvalidInputs(err) - } - - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case String, aggregateFunction: - default: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - switch right.Type() { - case String, aggregateFunction: - default: - err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for aggregate evaluation", operator, right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &comparisonExpr{ - left: left, - right: right, - operator: operator, - funcType: funcType, - }, nil - case Between, NotBetween: - if len(funcs) != 3 { - panic(fmt.Sprintf("too many values in funcs %v", funcs)) - } - - left := funcs[0] - if !left.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: left side expression %v evaluate to %v, not number", operator, left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - from := funcs[1] - if !from.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: from expression %v evaluate to %v, not number", operator, from, from.ReturnType()) - return nil, errInvalidDataType(err) - } - - to := funcs[2] - if !to.ReturnType().isNumberKind() { - err := fmt.Errorf("operator %v: to expression %v evaluate to %v, not number", operator, to, to.ReturnType()) - return nil, errInvalidDataType(err) - } - - if left.Type() == aggregateFunction || from.Type() == aggregateFunction || to.Type() == aggregateFunction { - funcType = aggregateFunction - switch left.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - switch from.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: from expression %v return type %v is incompatible for aggregate evaluation", operator, from, from.Type()) - return nil, errUnsupportedSQLOperation(err) - } - switch to.Type() { - case Int, Float, aggregateFunction: - default: - err := fmt.Errorf("operator %v: to expression %v return type %v is incompatible for aggregate evaluation", operator, to, to.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &comparisonExpr{ - left: left, - right: from, - to: to, - operator: operator, - funcType: funcType, - }, nil - case IsNull, IsNotNull: - if len(funcs) != 1 { - panic(fmt.Sprintf("too many values in funcs %v", funcs)) - } - - if funcs[0].Type() == aggregateFunction { - funcType = aggregateFunction - } - - if operator == IsNull { - operator = Equal - } else { - operator = NotEqual - } - - return &comparisonExpr{ - left: funcs[0], - right: newValueExpr(NewNull()), - operator: operator, - funcType: funcType, - }, nil - } - - return nil, errParseUnknownOperator(fmt.Errorf("unknown operator %v", operator)) -} diff --git a/pkg/s3select/sql/errors.go b/pkg/s3select/sql/errors.go index f97444a27..c6b225b63 100644 --- a/pkg/s3select/sql/errors.go +++ b/pkg/s3select/sql/errors.go @@ -43,42 +43,6 @@ func (err *s3Error) Error() string { return err.message } -func errUnsupportedSQLStructure(err error) *s3Error { - return &s3Error{ - code: "UnsupportedSqlStructure", - message: "Encountered an unsupported SQL structure. Check the SQL Reference.", - statusCode: 400, - cause: err, - } -} - -func errParseUnsupportedSelect(err error) *s3Error { - return &s3Error{ - code: "ParseUnsupportedSelect", - message: "The SQL expression contains an unsupported use of SELECT.", - statusCode: 400, - cause: err, - } -} - -func errParseAsteriskIsNotAloneInSelectList(err error) *s3Error { - return &s3Error{ - code: "ParseAsteriskIsNotAloneInSelectList", - message: "Other expressions are not allowed in the SELECT list when '*' is used without dot notation in the SQL expression.", - statusCode: 400, - cause: err, - } -} - -func errParseInvalidContextForWildcardInSelectList(err error) *s3Error { - return &s3Error{ - code: "ParseInvalidContextForWildcardInSelectList", - message: "Invalid use of * in SELECT list in the SQL expression.", - statusCode: 400, - cause: err, - } -} - func errInvalidDataType(err error) *s3Error { return &s3Error{ code: "InvalidDataType", @@ -88,55 +52,10 @@ func errInvalidDataType(err error) *s3Error { } } -func errUnsupportedFunction(err error) *s3Error { - return &s3Error{ - code: "UnsupportedFunction", - message: "Encountered an unsupported SQL function.", - statusCode: 400, - cause: err, - } -} - -func errParseNonUnaryAgregateFunctionCall(err error) *s3Error { - return &s3Error{ - code: "ParseNonUnaryAgregateFunctionCall", - message: "Only one argument is supported for aggregate functions in the SQL expression.", - statusCode: 400, - cause: err, - } -} - func errIncorrectSQLFunctionArgumentType(err error) *s3Error { return &s3Error{ code: "IncorrectSqlFunctionArgumentType", - message: "Incorrect type of arguments in function call in the SQL expression.", - statusCode: 400, - cause: err, - } -} - -func errEvaluatorInvalidArguments(err error) *s3Error { - return &s3Error{ - code: "EvaluatorInvalidArguments", - message: "Incorrect number of arguments in the function call in the SQL expression.", - statusCode: 400, - cause: err, - } -} - -func errUnsupportedSQLOperation(err error) *s3Error { - return &s3Error{ - code: "UnsupportedSqlOperation", - message: "Encountered an unsupported SQL operation.", - statusCode: 400, - cause: err, - } -} - -func errParseUnknownOperator(err error) *s3Error { - return &s3Error{ - code: "ParseUnknownOperator", - message: "The SQL expression contains an invalid operator.", + message: "Incorrect type of arguments in function call.", statusCode: 400, cause: err, } @@ -151,64 +70,28 @@ func errLikeInvalidInputs(err error) *s3Error { } } -func errExternalEvalException(err error) *s3Error { +func errQueryParseFailure(err error) *s3Error { return &s3Error{ - code: "ExternalEvalException", - message: "The query cannot be evaluated. Check the file and try again.", + code: "ParseSelectFailure", + message: err.Error(), statusCode: 400, cause: err, } } -func errValueParseFailure(err error) *s3Error { +func errQueryAnalysisFailure(err error) *s3Error { return &s3Error{ - code: "ValueParseFailure", - message: "Time stamp parse failure in the SQL expression.", + code: "InvalidQuery", + message: err.Error(), statusCode: 400, cause: err, } } -func errEvaluatorBindingDoesNotExist(err error) *s3Error { +func errBadTableName(err error) *s3Error { return &s3Error{ - code: "EvaluatorBindingDoesNotExist", - message: "A column name or a path provided does not exist in the SQL expression.", - statusCode: 400, - cause: err, - } -} - -func errInternalError(err error) *s3Error { - return &s3Error{ - code: "InternalError", - message: "Encountered an internal error.", - statusCode: 500, - cause: err, - } -} - -func errParseInvalidTypeParam(err error) *s3Error { - return &s3Error{ - code: "ParseInvalidTypeParam", - message: "The SQL expression contains an invalid parameter value.", - statusCode: 400, - cause: err, - } -} - -func errParseUnsupportedSyntax(err error) *s3Error { - return &s3Error{ - code: "ParseUnsupportedSyntax", - message: "The SQL expression contains unsupported syntax.", - statusCode: 400, - cause: err, - } -} - -func errInvalidKeyPath(err error) *s3Error { - return &s3Error{ - code: "InvalidKeyPath", - message: "Key path in the SQL expression is invalid.", + code: "BadTableName", + message: "The table name is not supported", statusCode: 400, cause: err, } diff --git a/pkg/s3select/sql/evaluate.go b/pkg/s3select/sql/evaluate.go new file mode 100644 index 000000000..3ee28597d --- /dev/null +++ b/pkg/s3select/sql/evaluate.go @@ -0,0 +1,361 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "strings" +) + +var ( + errInvalidASTNode = errors.New("invalid AST Node") + errExpectedBool = errors.New("expected bool") + errLikeNonStrArg = errors.New("LIKE clause requires string arguments") + errLikeInvalidEscape = errors.New("LIKE clause has invalid ESCAPE character") + errNotImplemented = errors.New("not implemented") +) + +// AST Node Evaluation functions +// +// During evaluation, the query is known to be valid, as analysis is +// complete. The only errors possible are due to value type +// mismatches, etc. +// +// If an aggregation node is present as a descendant (when +// e.prop.isAggregation is true), we call evalNode on all child nodes, +// check for errors, but do not perform any combining of the results +// of child nodes. The final result row is returned after all rows are +// processed, and the `getAggregate` function is called. + +func (e *AliasedExpression) evalNode(r Record) (*Value, error) { + return e.Expression.evalNode(r) +} + +func (e *Expression) evalNode(r Record) (*Value, error) { + if len(e.And) == 1 { + // In this case, result is not required to be boolean + // type. + return e.And[0].evalNode(r) + } + + // Compute OR of conditions + result := false + for _, ex := range e.And { + res, err := ex.evalNode(r) + if err != nil { + return nil, err + } + b, ok := res.ToBool() + if !ok { + return nil, errExpectedBool + } + result = result || b + } + return FromBool(result), nil +} + +func (e *AndCondition) evalNode(r Record) (*Value, error) { + if len(e.Condition) == 1 { + // In this case, result does not have to be boolean + return e.Condition[0].evalNode(r) + } + + // Compute AND of conditions + result := true + for _, ex := range e.Condition { + res, err := ex.evalNode(r) + if err != nil { + return nil, err + } + b, ok := res.ToBool() + if !ok { + return nil, errExpectedBool + } + result = result && b + } + return FromBool(result), nil +} + +func (e *Condition) evalNode(r Record) (*Value, error) { + if e.Operand != nil { + // In this case, result does not have to be boolean + return e.Operand.evalNode(r) + } + + // Compute NOT of condition + res, err := e.Not.evalNode(r) + if err != nil { + return nil, err + } + b, ok := res.ToBool() + if !ok { + return nil, errExpectedBool + } + return FromBool(!b), nil +} + +func (e *ConditionOperand) evalNode(r Record) (*Value, error) { + opVal, opErr := e.Operand.evalNode(r) + if opErr != nil || e.ConditionRHS == nil { + return opVal, opErr + } + + // Need to evaluate the ConditionRHS + switch { + case e.ConditionRHS.Compare != nil: + cmpRight, cmpRErr := e.ConditionRHS.Compare.Operand.evalNode(r) + if cmpRErr != nil { + return nil, cmpRErr + } + + b, err := opVal.compareOp(e.ConditionRHS.Compare.Operator, cmpRight) + return FromBool(b), err + + case e.ConditionRHS.Between != nil: + return e.ConditionRHS.Between.evalBetweenNode(r, opVal) + + case e.ConditionRHS.Like != nil: + return e.ConditionRHS.Like.evalLikeNode(r, opVal) + + case e.ConditionRHS.In != nil: + return e.ConditionRHS.In.evalInNode(r, opVal) + + default: + return nil, errInvalidASTNode + } +} + +func (e *Between) evalBetweenNode(r Record, arg *Value) (*Value, error) { + stVal, stErr := e.Start.evalNode(r) + if stErr != nil { + return nil, stErr + } + + endVal, endErr := e.End.evalNode(r) + if endErr != nil { + return nil, endErr + } + + part1, err1 := stVal.compareOp(opLte, arg) + if err1 != nil { + return nil, err1 + } + + part2, err2 := arg.compareOp(opLte, endVal) + if err2 != nil { + return nil, err2 + } + + result := part1 && part2 + if e.Not { + result = !result + } + + return FromBool(result), nil +} + +func (e *Like) evalLikeNode(r Record, arg *Value) (*Value, error) { + inferTypeAsString(arg) + + s, ok := arg.ToString() + if !ok { + err := errLikeNonStrArg + return nil, errLikeInvalidInputs(err) + } + + pattern, err1 := e.Pattern.evalNode(r) + if err1 != nil { + return nil, err1 + } + + // Infer pattern as string (in case it is untyped) + inferTypeAsString(pattern) + + patternStr, ok := pattern.ToString() + if !ok { + err := errLikeNonStrArg + return nil, errLikeInvalidInputs(err) + } + + escape := runeZero + if e.EscapeChar != nil { + escapeVal, err2 := e.EscapeChar.evalNode(r) + if err2 != nil { + return nil, err2 + } + + inferTypeAsString(escapeVal) + + escapeStr, ok := escapeVal.ToString() + if !ok { + err := errLikeNonStrArg + return nil, errLikeInvalidInputs(err) + } + + if len([]rune(escapeStr)) > 1 { + err := errLikeInvalidEscape + return nil, errLikeInvalidInputs(err) + } + } + + matchResult, err := evalSQLLike(s, patternStr, escape) + if err != nil { + return nil, err + } + + if e.Not { + matchResult = !matchResult + } + + return FromBool(matchResult), nil +} + +func (e *In) evalInNode(r Record, arg *Value) (*Value, error) { + result := false + for _, elt := range e.Expressions { + eltVal, err := elt.evalNode(r) + if err != nil { + return nil, err + } + + // FIXME: type inference? + + // Types must match. + if arg.vType != eltVal.vType { + // match failed. + continue + } + + if arg.value == eltVal.value { + result = true + break + } + } + return FromBool(result), nil +} + +func (e *Operand) evalNode(r Record) (*Value, error) { + lval, lerr := e.Left.evalNode(r) + if lerr != nil || len(e.Right) == 0 { + return lval, lerr + } + + // Process remaining child nodes - result must be + // numeric. This AST node is for terms separated by + or - + // symbols. + for _, rightTerm := range e.Right { + op := rightTerm.Op + rval, rerr := rightTerm.Right.evalNode(r) + if rerr != nil { + return nil, rerr + } + err := lval.arithOp(op, rval) + if err != nil { + return nil, err + } + } + return lval, nil +} + +func (e *MultOp) evalNode(r Record) (*Value, error) { + lval, lerr := e.Left.evalNode(r) + if lerr != nil || len(e.Right) == 0 { + return lval, lerr + } + + // Process other child nodes - result must be numeric. This + // AST node is for terms separated by *, / or % symbols. + for _, rightTerm := range e.Right { + op := rightTerm.Op + rval, rerr := rightTerm.Right.evalNode(r) + if rerr != nil { + return nil, rerr + } + + err := lval.arithOp(op, rval) + if err != nil { + return nil, err + } + } + return lval, nil +} + +func (e *UnaryTerm) evalNode(r Record) (*Value, error) { + if e.Negated == nil { + return e.Primary.evalNode(r) + } + + v, err := e.Negated.Term.evalNode(r) + if err != nil { + return nil, err + } + + inferTypeForArithOp(v) + if ival, ok := v.ToInt(); ok { + return FromInt(-ival), nil + } else if fval, ok := v.ToFloat(); ok { + return FromFloat(-fval), nil + } + return nil, errArithMismatchedTypes +} + +func (e *JSONPath) evalNode(r Record) (*Value, error) { + // Strip the table name from the keypath. + keypath := e.String() + ps := strings.SplitN(keypath, ".", 2) + if len(ps) == 2 { + keypath = ps[1] + } + return r.Get(keypath) +} + +func (e *PrimaryTerm) evalNode(r Record) (res *Value, err error) { + switch { + case e.Value != nil: + return e.Value.evalNode(r) + case e.JPathExpr != nil: + return e.JPathExpr.evalNode(r) + case e.SubExpression != nil: + return e.SubExpression.evalNode(r) + case e.FuncCall != nil: + return e.FuncCall.evalNode(r) + } + return nil, errInvalidASTNode +} + +func (e *FuncExpr) evalNode(r Record) (res *Value, err error) { + switch e.getFunctionName() { + case aggFnCount, aggFnAvg, aggFnMax, aggFnMin, aggFnSum: + return e.getAggregate() + default: + return e.evalSQLFnNode(r) + } +} + +// evalNode on a literal value is independent of the node being an +// aggregation or a row function - it always returns a value. +func (e *LitValue) evalNode(_ Record) (res *Value, err error) { + switch { + case e.Number != nil: + return floatToValue(*e.Number), nil + case e.String != nil: + return FromString(string(*e.String)), nil + case e.Boolean != nil: + return FromBool(bool(*e.Boolean)), nil + } + return FromNull(), nil +} diff --git a/pkg/s3select/sql/expr.go b/pkg/s3select/sql/expr.go deleted file mode 100644 index 4258f8dfd..000000000 --- a/pkg/s3select/sql/expr.go +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import ( - "fmt" -) - -// Expr - a SQL expression type. -type Expr interface { - AggregateValue() (*Value, error) - Eval(record Record) (*Value, error) - ReturnType() Type - Type() Type -} - -// aliasExpr - aliases expression by alias. -type aliasExpr struct { - alias string - expr Expr -} - -// String - returns string representation of this expression. -func (expr *aliasExpr) String() string { - return fmt.Sprintf("(%v AS %v)", expr.expr, expr.alias) -} - -// Eval - evaluates underlaying expression for given record and returns evaluated result. -func (expr *aliasExpr) Eval(record Record) (*Value, error) { - return expr.expr.Eval(record) -} - -// AggregateValue - returns aggregated value from underlaying expression. -func (expr *aliasExpr) AggregateValue() (*Value, error) { - return expr.expr.AggregateValue() -} - -// Type - returns underlaying expression type. -func (expr *aliasExpr) Type() Type { - return expr.expr.Type() -} - -// ReturnType - returns underlaying expression's return type. -func (expr *aliasExpr) ReturnType() Type { - return expr.expr.ReturnType() -} - -// newAliasExpr - creates new alias expression. -func newAliasExpr(alias string, expr Expr) *aliasExpr { - return &aliasExpr{alias, expr} -} - -// starExpr - asterisk (*) expression. -type starExpr struct { -} - -// String - returns string representation of this expression. -func (expr *starExpr) String() string { - return "*" -} - -// Eval - returns given args as map value. -func (expr *starExpr) Eval(record Record) (*Value, error) { - return newRecordValue(record), nil -} - -// AggregateValue - returns nil value. -func (expr *starExpr) AggregateValue() (*Value, error) { - return nil, nil -} - -// Type - returns record type. -func (expr *starExpr) Type() Type { - return record -} - -// ReturnType - returns record as return type. -func (expr *starExpr) ReturnType() Type { - return record -} - -// newStarExpr - returns new asterisk (*) expression. -func newStarExpr() *starExpr { - return &starExpr{} -} - -type valueExpr struct { - value *Value -} - -func (expr *valueExpr) String() string { - return expr.value.String() -} - -func (expr *valueExpr) Eval(record Record) (*Value, error) { - return expr.value, nil -} - -func (expr *valueExpr) AggregateValue() (*Value, error) { - return expr.value, nil -} - -func (expr *valueExpr) Type() Type { - return expr.value.Type() -} - -func (expr *valueExpr) ReturnType() Type { - return expr.value.Type() -} - -func newValueExpr(value *Value) *valueExpr { - return &valueExpr{value: value} -} - -type columnExpr struct { - name string -} - -func (expr *columnExpr) String() string { - return expr.name -} - -func (expr *columnExpr) Eval(record Record) (*Value, error) { - value, err := record.Get(expr.name) - if err != nil { - return nil, errEvaluatorBindingDoesNotExist(err) - } - - return value, nil -} - -func (expr *columnExpr) AggregateValue() (*Value, error) { - return nil, nil -} - -func (expr *columnExpr) Type() Type { - return column -} - -func (expr *columnExpr) ReturnType() Type { - return column -} - -func newColumnExpr(columnName string) *columnExpr { - return &columnExpr{name: columnName} -} diff --git a/pkg/s3select/sql/funceval.go b/pkg/s3select/sql/funceval.go new file mode 100644 index 000000000..132383281 --- /dev/null +++ b/pkg/s3select/sql/funceval.go @@ -0,0 +1,433 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +// FuncName - SQL function name. +type FuncName string + +// SQL Function name constants +const ( + // Conditionals + sqlFnCoalesce FuncName = "COALESCE" + sqlFnNullIf FuncName = "NULLIF" + + // Conversion + sqlFnCast FuncName = "CAST" + + // Date and time + sqlFnDateAdd FuncName = "DATE_ADD" + sqlFnDateDiff FuncName = "DATE_DIFF" + sqlFnExtract FuncName = "EXTRACT" + sqlFnToString FuncName = "TO_STRING" + sqlFnToTimestamp FuncName = "TO_TIMESTAMP" + sqlFnUTCNow FuncName = "UTCNOW" + + // String + sqlFnCharLength FuncName = "CHAR_LENGTH" + sqlFnCharacterLength FuncName = "CHARACTER_LENGTH" + sqlFnLower FuncName = "LOWER" + sqlFnSubstring FuncName = "SUBSTRING" + sqlFnTrim FuncName = "TRIM" + sqlFnUpper FuncName = "UPPER" +) + +// Allowed cast types +const ( + castBool = "BOOL" + castInt = "INT" + castInteger = "INTEGER" + castString = "STRING" + castFloat = "FLOAT" + castDecimal = "DECIMAL" + castNumeric = "NUMERIC" + castTimestamp = "TIMESTAMP" +) + +var ( + errUnimplementedCast = errors.New("This cast not yet implemented") + errNonStringTrimArg = errors.New("TRIM() received a non-string argument") +) + +func (e *FuncExpr) getFunctionName() FuncName { + switch { + case e.SFunc != nil: + return FuncName(strings.ToUpper(e.SFunc.FunctionName)) + case e.Count != nil: + return FuncName(aggFnCount) + case e.Cast != nil: + return sqlFnCast + case e.Substring != nil: + return sqlFnSubstring + case e.Extract != nil: + return sqlFnExtract + case e.Trim != nil: + return sqlFnTrim + default: + return "" + } +} + +// evalSQLFnNode assumes that the FuncExpr is not an aggregation +// function. +func (e *FuncExpr) evalSQLFnNode(r Record) (res *Value, err error) { + // Handle functions that have phrase arguments + switch e.getFunctionName() { + case sqlFnCast: + expr := e.Cast.Expr + res, err = expr.castTo(r, strings.ToUpper(e.Cast.CastType)) + return + + case sqlFnSubstring: + return handleSQLSubstring(r, e.Substring) + + case sqlFnExtract: + return nil, errNotImplemented + + case sqlFnTrim: + return handleSQLTrim(r, e.Trim) + } + + // For all simple argument functions, we evaluate the arguments here + argVals := make([]*Value, len(e.SFunc.ArgsList)) + for i, arg := range e.SFunc.ArgsList { + argVals[i], err = arg.evalNode(r) + if err != nil { + return nil, err + } + } + + switch e.getFunctionName() { + case sqlFnCoalesce: + return coalesce(r, argVals) + + case sqlFnNullIf: + return nullif(r, argVals[0], argVals[1]) + + case sqlFnCharLength, sqlFnCharacterLength: + return charlen(r, argVals[0]) + + case sqlFnLower: + return lowerCase(r, argVals[0]) + + case sqlFnUpper: + return upperCase(r, argVals[0]) + + case sqlFnDateAdd, sqlFnDateDiff, sqlFnToString, sqlFnToTimestamp, sqlFnUTCNow: + // TODO: implement + fallthrough + + default: + return nil, errInvalidASTNode + } +} + +func coalesce(r Record, args []*Value) (res *Value, err error) { + for _, arg := range args { + if arg.IsNull() { + continue + } + return arg, nil + } + return FromNull(), nil +} + +func nullif(r Record, v1, v2 *Value) (res *Value, err error) { + // Handle Null cases + if v1.IsNull() || v2.IsNull() { + return v1, nil + } + + err = inferTypesForCmp(v1, v2) + if err != nil { + return nil, err + } + + atleastOneNumeric := v1.isNumeric() || v2.isNumeric() + bothNumeric := v1.isNumeric() && v2.isNumeric() + if atleastOneNumeric || !bothNumeric { + return v1, nil + } + + if v1.vType != v2.vType { + return v1, nil + } + + cmpResult, cmpErr := v1.compareOp(opEq, v2) + if cmpErr != nil { + return nil, cmpErr + } + + if cmpResult { + return FromNull(), nil + } + + return v1, nil +} + +func charlen(r Record, v *Value) (*Value, error) { + inferTypeAsString(v) + s, ok := v.ToString() + if !ok { + err := fmt.Errorf("%s/%s expects a string argument", sqlFnCharLength, sqlFnCharacterLength) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + return FromInt(int64(len(s))), nil +} + +func lowerCase(r Record, v *Value) (*Value, error) { + inferTypeAsString(v) + s, ok := v.ToString() + if !ok { + err := fmt.Errorf("%s expects a string argument", sqlFnLower) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + return FromString(strings.ToLower(s)), nil +} + +func upperCase(r Record, v *Value) (*Value, error) { + inferTypeAsString(v) + s, ok := v.ToString() + if !ok { + err := fmt.Errorf("%s expects a string argument", sqlFnUpper) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + return FromString(strings.ToUpper(s)), nil +} + +func handleSQLSubstring(r Record, e *SubstringFunc) (val *Value, err error) { + // Both forms `SUBSTRING('abc' FROM 2 FOR 1)` and + // SUBSTRING('abc', 2, 1) are supported. + + // Evaluate the string argument + v1, err := e.Expr.evalNode(r) + if err != nil { + return nil, err + } + inferTypeAsString(v1) + s, ok := v1.ToString() + if !ok { + err := fmt.Errorf("Incorrect argument type passed to %s", sqlFnSubstring) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + + // Assemble other arguments + arg2, arg3 := e.From, e.For + // Check if the second form of substring is being used + if e.From == nil { + arg2, arg3 = e.Arg2, e.Arg3 + } + + // Evaluate the FROM argument + v2, err := arg2.evalNode(r) + if err != nil { + return nil, err + } + inferTypeForArithOp(v2) + startIdx, ok := v2.ToInt() + if !ok { + err := fmt.Errorf("Incorrect type for start index argument in %s", sqlFnSubstring) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + + length := -1 + // Evaluate the optional FOR argument + if arg3 != nil { + v3, err := arg3.evalNode(r) + if err != nil { + return nil, err + } + inferTypeForArithOp(v3) + lenInt, ok := v3.ToInt() + if !ok { + err := fmt.Errorf("Incorrect type for length argument in %s", sqlFnSubstring) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + length = int(lenInt) + if length < 0 { + err := fmt.Errorf("Negative length argument in %s", sqlFnSubstring) + return nil, errIncorrectSQLFunctionArgumentType(err) + } + } + + res, err := evalSQLSubstring(s, int(startIdx), length) + return FromString(res), err +} + +func handleSQLTrim(r Record, e *TrimFunc) (res *Value, err error) { + charsV, cerr := e.TrimChars.evalNode(r) + if cerr != nil { + return nil, cerr + } + inferTypeAsString(charsV) + chars, ok := charsV.ToString() + if !ok { + return nil, errNonStringTrimArg + } + + fromV, ferr := e.TrimFrom.evalNode(r) + if ferr != nil { + return nil, ferr + } + from, ok := fromV.ToString() + if !ok { + return nil, errNonStringTrimArg + } + + result, terr := evalSQLTrim(e.TrimWhere, chars, from) + if terr != nil { + return nil, terr + } + return FromString(result), nil +} + +func errUnsupportedCast(fromType, toType string) error { + return fmt.Errorf("Cannot cast from %v to %v", fromType, toType) +} + +func errCastFailure(msg string) error { + return fmt.Errorf("Error casting: %s", msg) +} + +func (e *Expression) castTo(r Record, castType string) (res *Value, err error) { + v, err := e.evalNode(r) + if err != nil { + return nil, err + } + fmt.Println("Cast to ", castType) + + switch castType { + case castInt, castInteger: + i, err := intCast(v) + return FromInt(i), err + + case castFloat: + f, err := floatCast(v) + return FromFloat(f), err + + case castString: + s, err := stringCast(v) + return FromString(s), err + + case castBool, castDecimal, castNumeric, castTimestamp: + fallthrough + + default: + return nil, errUnimplementedCast + } +} + +func intCast(v *Value) (int64, error) { + // This conversion truncates floating point numbers to + // integer. + strToInt := func(s string) (int64, bool) { + i, errI := strconv.ParseInt(s, 10, 64) + if errI == nil { + return i, true + } + f, errF := strconv.ParseFloat(s, 64) + if errF == nil { + return int64(f), true + } + return 0, false + } + + switch v.vType { + case typeFloat: + // Truncate fractional part + return int64(v.value.(float64)), nil + case typeInt: + return v.value.(int64), nil + case typeString: + // Parse as number, truncate floating point if + // needed. + s, _ := v.ToString() + res, ok := strToInt(s) + if !ok { + return 0, errCastFailure("could not parse as int") + } + return res, nil + case typeBytes: + // Parse as number, truncate floating point if + // needed. + b, _ := v.ToBytes() + s := string(b) + res, ok := strToInt(s) + if !ok { + return 0, errCastFailure("could not parse as int") + } + return res, nil + + default: + return 0, errUnsupportedCast(v.GetTypeString(), castInt) + } +} + +func floatCast(v *Value) (float64, error) { + switch v.vType { + case typeFloat: + return v.value.(float64), nil + case typeInt: + return float64(v.value.(int64)), nil + case typeString: + f, err := strconv.ParseFloat(v.value.(string), 64) + if err != nil { + return 0, errCastFailure("could not parse as float") + } + return f, nil + case typeBytes: + b, _ := v.ToBytes() + f, err := strconv.ParseFloat(string(b), 64) + if err != nil { + return 0, errCastFailure("could not parse as float") + } + return f, nil + default: + return 0, errUnsupportedCast(v.GetTypeString(), castFloat) + } +} + +func stringCast(v *Value) (string, error) { + switch v.vType { + case typeFloat: + f, _ := v.ToFloat() + return fmt.Sprintf("%v", f), nil + case typeInt: + i, _ := v.ToInt() + return fmt.Sprintf("%v", i), nil + case typeString: + s, _ := v.ToString() + return s, nil + case typeBytes: + b, _ := v.ToBytes() + return string(b), nil + case typeBool: + b, _ := v.ToBool() + return fmt.Sprintf("%v", b), nil + case typeNull: + // FIXME: verify this case is correct + return fmt.Sprintf("NULL"), nil + } + // This does not happen + return "", nil +} diff --git a/pkg/s3select/sql/funcexpr.go b/pkg/s3select/sql/funcexpr.go deleted file mode 100644 index 9ea1ffed0..000000000 --- a/pkg/s3select/sql/funcexpr.go +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import ( - "fmt" - "strings" - "time" -) - -// FuncName - SQL function name. -type FuncName string - -const ( - // Avg - aggregate SQL function AVG(). - Avg FuncName = "AVG" - - // Count - aggregate SQL function COUNT(). - Count FuncName = "COUNT" - - // Max - aggregate SQL function MAX(). - Max FuncName = "MAX" - - // Min - aggregate SQL function MIN(). - Min FuncName = "MIN" - - // Sum - aggregate SQL function SUM(). - Sum FuncName = "SUM" - - // Coalesce - conditional SQL function COALESCE(). - Coalesce FuncName = "COALESCE" - - // NullIf - conditional SQL function NULLIF(). - NullIf FuncName = "NULLIF" - - // ToTimestamp - conversion SQL function TO_TIMESTAMP(). - ToTimestamp FuncName = "TO_TIMESTAMP" - - // UTCNow - date SQL function UTCNOW(). - UTCNow FuncName = "UTCNOW" - - // CharLength - string SQL function CHAR_LENGTH(). - CharLength FuncName = "CHAR_LENGTH" - - // CharacterLength - string SQL function CHARACTER_LENGTH() same as CHAR_LENGTH(). - CharacterLength FuncName = "CHARACTER_LENGTH" - - // Lower - string SQL function LOWER(). - Lower FuncName = "LOWER" - - // Substring - string SQL function SUBSTRING(). - Substring FuncName = "SUBSTRING" - - // Trim - string SQL function TRIM(). - Trim FuncName = "TRIM" - - // Upper - string SQL function UPPER(). - Upper FuncName = "UPPER" - - // DateAdd FuncName = "DATE_ADD" - // DateDiff FuncName = "DATE_DIFF" - // Extract FuncName = "EXTRACT" - // ToString FuncName = "TO_STRING" - // Cast FuncName = "CAST" // CAST('2007-04-05T14:30Z' AS TIMESTAMP) -) - -func isAggregateFuncName(s string) bool { - switch FuncName(s) { - case Avg, Count, Max, Min, Sum: - return true - } - - return false -} - -func callForNumber(f Expr, record Record) (*Value, error) { - value, err := f.Eval(record) - if err != nil { - return nil, err - } - - if !value.Type().isNumber() { - err := fmt.Errorf("%v evaluated to %v; not to number", f, value.Type()) - return nil, errExternalEvalException(err) - } - - return value, nil -} - -func callForInt(f Expr, record Record) (*Value, error) { - value, err := f.Eval(record) - if err != nil { - return nil, err - } - - if value.Type() != Int { - err := fmt.Errorf("%v evaluated to %v; not to int", f, value.Type()) - return nil, errExternalEvalException(err) - } - - return value, nil -} - -func callForString(f Expr, record Record) (*Value, error) { - value, err := f.Eval(record) - if err != nil { - return nil, err - } - - if value.Type() != String { - err := fmt.Errorf("%v evaluated to %v; not to string", f, value.Type()) - return nil, errExternalEvalException(err) - } - - return value, nil -} - -// funcExpr - SQL function. -type funcExpr struct { - args []Expr - name FuncName - - sumValue float64 - countValue int64 - maxValue float64 - minValue float64 -} - -// String - returns string representation of this function. -func (f *funcExpr) String() string { - var argStrings []string - for _, arg := range f.args { - argStrings = append(argStrings, fmt.Sprintf("%v", arg)) - } - - return fmt.Sprintf("%v(%v)", f.name, strings.Join(argStrings, ",")) -} - -func (f *funcExpr) sum(record Record) (*Value, error) { - value, err := callForNumber(f.args[0], record) - if err != nil { - return nil, err - } - - f.sumValue += value.FloatValue() - f.countValue++ - return nil, nil -} - -func (f *funcExpr) count(record Record) (*Value, error) { - value, err := f.args[0].Eval(record) - if err != nil { - return nil, err - } - - if value.valueType != Null { - f.countValue++ - } - - return nil, nil -} - -func (f *funcExpr) max(record Record) (*Value, error) { - value, err := callForNumber(f.args[0], record) - if err != nil { - return nil, err - } - - v := value.FloatValue() - if v > f.maxValue { - f.maxValue = v - } - - return nil, nil -} - -func (f *funcExpr) min(record Record) (*Value, error) { - value, err := callForNumber(f.args[0], record) - if err != nil { - return nil, err - } - - v := value.FloatValue() - if v < f.minValue { - f.minValue = v - } - return nil, nil -} - -func (f *funcExpr) charLength(record Record) (*Value, error) { - value, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - return NewInt(int64(len(value.StringValue()))), nil -} - -func (f *funcExpr) trim(record Record) (*Value, error) { - value, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - return NewString(strings.TrimSpace(value.StringValue())), nil -} - -func (f *funcExpr) lower(record Record) (*Value, error) { - value, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - return NewString(strings.ToLower(value.StringValue())), nil -} - -func (f *funcExpr) upper(record Record) (*Value, error) { - value, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - return NewString(strings.ToUpper(value.StringValue())), nil -} - -func (f *funcExpr) substring(record Record) (*Value, error) { - stringValue, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - offsetValue, err := callForInt(f.args[1], record) - if err != nil { - return nil, err - } - - var lengthValue *Value - if len(f.args) == 3 { - lengthValue, err = callForInt(f.args[2], record) - if err != nil { - return nil, err - } - } - - value := stringValue.StringValue() - offset := int(offsetValue.FloatValue()) - if offset < 0 || offset > len(value) { - offset = 0 - } - length := len(value) - if lengthValue != nil { - length = int(lengthValue.FloatValue()) - if length < 0 || length > len(value) { - length = len(value) - } - } - - return NewString(value[offset:length]), nil -} - -func (f *funcExpr) coalesce(record Record) (*Value, error) { - values := make([]*Value, len(f.args)) - var err error - for i := range f.args { - values[i], err = f.args[i].Eval(record) - if err != nil { - return nil, err - } - } - - for i := range values { - if values[i].Type() != Null { - return values[i], nil - } - } - - return values[0], nil -} - -func (f *funcExpr) nullIf(record Record) (*Value, error) { - value1, err := f.args[0].Eval(record) - if err != nil { - return nil, err - } - - value2, err := f.args[1].Eval(record) - if err != nil { - return nil, err - } - - result, err := equal(value1, value2) - if err != nil { - return nil, err - } - - if result { - return NewNull(), nil - } - - return value1, nil -} - -func (f *funcExpr) toTimeStamp(record Record) (*Value, error) { - value, err := callForString(f.args[0], record) - if err != nil { - return nil, err - } - - t, err := time.Parse(time.RFC3339, value.StringValue()) - if err != nil { - err := fmt.Errorf("%v: value '%v': %v", f, value, err) - return nil, errValueParseFailure(err) - } - - return NewTime(t), nil -} - -func (f *funcExpr) utcNow(record Record) (*Value, error) { - return NewTime(time.Now().UTC()), nil -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *funcExpr) Eval(record Record) (*Value, error) { - switch f.name { - case Avg, Sum: - return f.sum(record) - case Count: - return f.count(record) - case Max: - return f.max(record) - case Min: - return f.min(record) - case Coalesce: - return f.coalesce(record) - case NullIf: - return f.nullIf(record) - case ToTimestamp: - return f.toTimeStamp(record) - case UTCNow: - return f.utcNow(record) - case Substring: - return f.substring(record) - case CharLength, CharacterLength: - return f.charLength(record) - case Trim: - return f.trim(record) - case Lower: - return f.lower(record) - case Upper: - return f.upper(record) - } - - panic(fmt.Sprintf("unsupported aggregate function %v", f.name)) -} - -// AggregateValue - returns aggregated value. -func (f *funcExpr) AggregateValue() (*Value, error) { - switch f.name { - case Avg: - return NewFloat(f.sumValue / float64(f.countValue)), nil - case Count: - return NewInt(f.countValue), nil - case Max: - return NewFloat(f.maxValue), nil - case Min: - return NewFloat(f.minValue), nil - case Sum: - return NewFloat(f.sumValue), nil - } - - err := fmt.Errorf("%v is not aggreate function", f) - return nil, errExternalEvalException(err) -} - -// Type - returns Function or aggregateFunction type. -func (f *funcExpr) Type() Type { - switch f.name { - case Avg, Count, Max, Min, Sum: - return aggregateFunction - } - - return function -} - -// ReturnType - returns respective primitive type depending on SQL function. -func (f *funcExpr) ReturnType() Type { - switch f.name { - case Avg, Max, Min, Sum: - return Float - case Count: - return Int - case CharLength, CharacterLength, Trim, Lower, Upper, Substring: - return String - case ToTimestamp, UTCNow: - return Timestamp - case Coalesce, NullIf: - return column - } - - return function -} - -// newFuncExpr - creates new SQL function. -func newFuncExpr(funcName FuncName, funcs ...Expr) (*funcExpr, error) { - switch funcName { - case Avg, Max, Min, Sum: - if len(funcs) != 1 { - err := fmt.Errorf("%v(): exactly one argument expected; got %v", funcName, len(funcs)) - return nil, errParseNonUnaryAgregateFunctionCall(err) - } - - if !funcs[0].ReturnType().isNumberKind() { - err := fmt.Errorf("%v(): argument %v evaluate to %v, not number", funcName, funcs[0], funcs[0].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case Count: - if len(funcs) != 1 { - err := fmt.Errorf("%v(): exactly one argument expected; got %v", funcName, len(funcs)) - return nil, errParseNonUnaryAgregateFunctionCall(err) - } - - switch funcs[0].ReturnType() { - case Null, Bool, Int, Float, String, Timestamp, column, record: - default: - err := fmt.Errorf("%v(): argument %v evaluate to %v is incompatible", funcName, funcs[0], funcs[0].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case CharLength, CharacterLength, Trim, Lower, Upper, ToTimestamp: - if len(funcs) != 1 { - err := fmt.Errorf("%v(): exactly one argument expected; got %v", funcName, len(funcs)) - return nil, errEvaluatorInvalidArguments(err) - } - - if !funcs[0].ReturnType().isStringKind() { - err := fmt.Errorf("%v(): argument %v evaluate to %v, not string", funcName, funcs[0], funcs[0].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case Coalesce: - if len(funcs) < 1 { - err := fmt.Errorf("%v(): one or more argument expected; got %v", funcName, len(funcs)) - return nil, errEvaluatorInvalidArguments(err) - } - - for i := range funcs { - if !funcs[i].ReturnType().isBaseKind() { - err := fmt.Errorf("%v(): argument-%v %v evaluate to %v is incompatible", funcName, i+1, funcs[i], funcs[i].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case NullIf: - if len(funcs) != 2 { - err := fmt.Errorf("%v(): exactly two arguments expected; got %v", funcName, len(funcs)) - return nil, errEvaluatorInvalidArguments(err) - } - - if !funcs[0].ReturnType().isBaseKind() { - err := fmt.Errorf("%v(): argument-1 %v evaluate to %v is incompatible", funcName, funcs[0], funcs[0].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - if !funcs[1].ReturnType().isBaseKind() { - err := fmt.Errorf("%v(): argument-2 %v evaluate to %v is incompatible", funcName, funcs[1], funcs[1].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case UTCNow: - if len(funcs) != 0 { - err := fmt.Errorf("%v(): no argument expected; got %v", funcName, len(funcs)) - return nil, errEvaluatorInvalidArguments(err) - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - - case Substring: - if len(funcs) < 2 || len(funcs) > 3 { - err := fmt.Errorf("%v(): exactly two or three arguments expected; got %v", funcName, len(funcs)) - return nil, errEvaluatorInvalidArguments(err) - } - - if !funcs[0].ReturnType().isStringKind() { - err := fmt.Errorf("%v(): argument-1 %v evaluate to %v, not string", funcName, funcs[0], funcs[0].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - if !funcs[1].ReturnType().isIntKind() { - err := fmt.Errorf("%v(): argument-2 %v evaluate to %v, not int", funcName, funcs[1], funcs[1].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - - if len(funcs) > 2 { - if !funcs[2].ReturnType().isIntKind() { - err := fmt.Errorf("%v(): argument-3 %v evaluate to %v, not int", funcName, funcs[2], funcs[2].ReturnType()) - return nil, errIncorrectSQLFunctionArgumentType(err) - } - } - - return &funcExpr{ - args: funcs, - name: funcName, - }, nil - } - - return nil, errUnsupportedFunction(fmt.Errorf("unknown function name %v", funcName)) -} diff --git a/pkg/s3select/sql/logicalexpr.go b/pkg/s3select/sql/logicalexpr.go deleted file mode 100644 index d307200f7..000000000 --- a/pkg/s3select/sql/logicalexpr.go +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import "fmt" - -// andExpr - logical AND function. -type andExpr struct { - left Expr - right Expr - funcType Type -} - -// String - returns string representation of this function. -func (f *andExpr) String() string { - return fmt.Sprintf("(%v AND %v)", f.left, f.right) -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *andExpr) Eval(record Record) (*Value, error) { - leftValue, err := f.left.Eval(record) - if err != nil { - return nil, err - } - - if f.funcType == aggregateFunction { - _, err = f.right.Eval(record) - return nil, err - } - - if leftValue.Type() != Bool { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to bool", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - - if !leftValue.BoolValue() { - return leftValue, nil - } - - rightValue, err := f.right.Eval(record) - if err != nil { - return nil, err - } - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return rightValue, nil -} - -// AggregateValue - returns aggregated value. -func (f *andExpr) AggregateValue() (*Value, error) { - if f.funcType != aggregateFunction { - err := fmt.Errorf("%v is not aggreate expression", f) - return nil, errExternalEvalException(err) - } - - leftValue, err := f.left.AggregateValue() - if err != nil { - return nil, err - } - if leftValue.Type() != Bool { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to bool", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - - if !leftValue.BoolValue() { - return leftValue, nil - } - - rightValue, err := f.right.AggregateValue() - if err != nil { - return nil, err - } - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return rightValue, nil -} - -// Type - returns logicalFunction or aggregateFunction type. -func (f *andExpr) Type() Type { - return f.funcType -} - -// ReturnType - returns Bool as return type. -func (f *andExpr) ReturnType() Type { - return Bool -} - -// newAndExpr - creates new AND logical function. -func newAndExpr(left, right Expr) (*andExpr, error) { - if !left.ReturnType().isBoolKind() { - err := fmt.Errorf("operator AND: left side expression %v evaluate to %v, not bool", left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - if !right.ReturnType().isBoolKind() { - err := fmt.Errorf("operator AND: right side expression %v evaluate to %v; not bool", right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - funcType := logicalFunction - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - if left.Type() == column { - err := fmt.Errorf("operator AND: left side expression %v return type %v is incompatible for aggregate evaluation", left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - - if right.Type() == column { - err := fmt.Errorf("operator AND: right side expression %v return type %v is incompatible for aggregate evaluation", right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &andExpr{ - left: left, - right: right, - funcType: funcType, - }, nil -} - -// orExpr - logical OR function. -type orExpr struct { - left Expr - right Expr - funcType Type -} - -// String - returns string representation of this function. -func (f *orExpr) String() string { - return fmt.Sprintf("(%v OR %v)", f.left, f.right) -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *orExpr) Eval(record Record) (*Value, error) { - leftValue, err := f.left.Eval(record) - if err != nil { - return nil, err - } - - if f.funcType == aggregateFunction { - _, err = f.right.Eval(record) - return nil, err - } - - if leftValue.Type() != Bool { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to bool", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - - if leftValue.BoolValue() { - return leftValue, nil - } - - rightValue, err := f.right.Eval(record) - if err != nil { - return nil, err - } - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return rightValue, nil -} - -// AggregateValue - returns aggregated value. -func (f *orExpr) AggregateValue() (*Value, error) { - if f.funcType != aggregateFunction { - err := fmt.Errorf("%v is not aggreate expression", f) - return nil, errExternalEvalException(err) - } - - leftValue, err := f.left.AggregateValue() - if err != nil { - return nil, err - } - if leftValue.Type() != Bool { - err := fmt.Errorf("%v: left side expression evaluated to %v; not to bool", f, leftValue.Type()) - return nil, errExternalEvalException(err) - } - - if leftValue.BoolValue() { - return leftValue, nil - } - - rightValue, err := f.right.AggregateValue() - if err != nil { - return nil, err - } - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return rightValue, nil -} - -// Type - returns logicalFunction or aggregateFunction type. -func (f *orExpr) Type() Type { - return f.funcType -} - -// ReturnType - returns Bool as return type. -func (f *orExpr) ReturnType() Type { - return Bool -} - -// newOrExpr - creates new OR logical function. -func newOrExpr(left, right Expr) (*orExpr, error) { - if !left.ReturnType().isBoolKind() { - err := fmt.Errorf("operator OR: left side expression %v evaluate to %v, not bool", left, left.ReturnType()) - return nil, errInvalidDataType(err) - } - - if !right.ReturnType().isBoolKind() { - err := fmt.Errorf("operator OR: right side expression %v evaluate to %v; not bool", right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - funcType := logicalFunction - if left.Type() == aggregateFunction || right.Type() == aggregateFunction { - funcType = aggregateFunction - if left.Type() == column { - err := fmt.Errorf("operator OR: left side expression %v return type %v is incompatible for aggregate evaluation", left, left.Type()) - return nil, errUnsupportedSQLOperation(err) - } - - if right.Type() == column { - err := fmt.Errorf("operator OR: right side expression %v return type %v is incompatible for aggregate evaluation", right, right.Type()) - return nil, errUnsupportedSQLOperation(err) - } - } - - return &orExpr{ - left: left, - right: right, - funcType: funcType, - }, nil -} - -// notExpr - logical NOT function. -type notExpr struct { - right Expr - funcType Type -} - -// String - returns string representation of this function. -func (f *notExpr) String() string { - return fmt.Sprintf("(%v)", f.right) -} - -// Call - evaluates this function for given arg values and returns result as Value. -func (f *notExpr) Eval(record Record) (*Value, error) { - rightValue, err := f.right.Eval(record) - if err != nil { - return nil, err - } - - if f.funcType == aggregateFunction { - return nil, nil - } - - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(!rightValue.BoolValue()), nil -} - -// AggregateValue - returns aggregated value. -func (f *notExpr) AggregateValue() (*Value, error) { - if f.funcType != aggregateFunction { - err := fmt.Errorf("%v is not aggreate expression", f) - return nil, errExternalEvalException(err) - } - - rightValue, err := f.right.AggregateValue() - if err != nil { - return nil, err - } - if rightValue.Type() != Bool { - err := fmt.Errorf("%v: right side expression evaluated to %v; not to bool", f, rightValue.Type()) - return nil, errExternalEvalException(err) - } - - return NewBool(!rightValue.BoolValue()), nil -} - -// Type - returns logicalFunction or aggregateFunction type. -func (f *notExpr) Type() Type { - return f.funcType -} - -// ReturnType - returns Bool as return type. -func (f *notExpr) ReturnType() Type { - return Bool -} - -// newNotExpr - creates new NOT logical function. -func newNotExpr(right Expr) (*notExpr, error) { - if !right.ReturnType().isBoolKind() { - err := fmt.Errorf("operator NOT: right side expression %v evaluate to %v; not bool", right, right.ReturnType()) - return nil, errInvalidDataType(err) - } - - funcType := logicalFunction - if right.Type() == aggregateFunction { - funcType = aggregateFunction - } - - return ¬Expr{ - right: right, - funcType: funcType, - }, nil -} diff --git a/pkg/s3select/sql/parser.go b/pkg/s3select/sql/parser.go new file mode 100644 index 000000000..bfdb7d0e4 --- /dev/null +++ b/pkg/s3select/sql/parser.go @@ -0,0 +1,329 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "strings" + + "github.com/alecthomas/participle" + "github.com/alecthomas/participle/lexer" +) + +// Types with custom Capture interface for parsing + +// Boolean is a type for a parsed Boolean literal +type Boolean bool + +// Capture interface used by participle +func (b *Boolean) Capture(values []string) error { + *b = strings.ToLower(values[0]) == "true" + return nil +} + +// LiteralString is a type for parsed SQL string literals +type LiteralString string + +// Capture interface used by participle +func (ls *LiteralString) Capture(values []string) error { + // Remove enclosing single quote + n := len(values[0]) + r := values[0][1 : n-1] + // Translate doubled quotes + *ls = LiteralString(strings.Replace(r, "''", "'", -1)) + return nil +} + +// ObjectKey is a type for parsed strings occurring in key paths +type ObjectKey struct { + Lit *LiteralString `parser:" \"[\" @LitString \"]\""` + ID *Identifier `parser:"| \".\" @@"` +} + +// QuotedIdentifier is a type for parsed strings that are double +// quoted. +type QuotedIdentifier string + +// Capture inferface used by participle +func (qi *QuotedIdentifier) Capture(values []string) error { + // Remove enclosing quotes + n := len(values[0]) + r := values[0][1 : n-1] + + // Translate doubled quotes + *qi = QuotedIdentifier(strings.Replace(r, `""`, `"`, -1)) + return nil +} + +// Types representing AST of SQL statement. Only SELECT is supported. + +// Select is the top level AST node type +type Select struct { + Expression *SelectExpression `parser:"\"SELECT\" @@"` + From *TableExpression `parser:"\"FROM\" @@"` + Where *Expression `parser:"[ \"WHERE\" @@ ]"` + Limit *LitValue `parser:"[ \"LIMIT\" @@ ]"` +} + +// SelectExpression represents the items requested in the select +// statement +type SelectExpression struct { + All bool `parser:" @\"*\""` + Expressions []*AliasedExpression `parser:"| @@ { \",\" @@ }"` + + prop qProp +} + +// TableExpression represents the FROM clause +type TableExpression struct { + Table *JSONPath `parser:"@@"` + As string `parser:"( \"AS\"? @Ident )?"` +} + +// JSONPathElement represents a keypath component +type JSONPathElement struct { + Key *ObjectKey `parser:" @@"` // ['name'] and .name forms + Index *uint64 `parser:"| \"[\" @Number \"]\""` // [3] form + ObjectWildcard bool `parser:"| @\".*\""` // .* form + ArrayWildcard bool `parser:"| @\"[*]\""` // [*] form +} + +// JSONPath represents a keypath +type JSONPath struct { + BaseKey *Identifier `parser:" @@"` + PathExpr []*JSONPathElement `parser:"(@@)*"` +} + +// AliasedExpression is an expression that can be optionally named +type AliasedExpression struct { + Expression *Expression `parser:"@@"` + As string `parser:"[ \"AS\" @Ident ]"` +} + +// Grammar for Expression +// +// Expression → AndCondition ("OR" AndCondition)* +// AndCondition → Condition ("AND" Condition)* +// Condition → "NOT" Condition | ConditionExpression +// ConditionExpression → ValueExpression ("=" | "<>" | "<=" | ">=" | "<" | ">") ValueExpression +// | ValueExpression "LIKE" ValueExpression ("ESCAPE" LitString)? +// | ValueExpression ("NOT"? "BETWEEN" ValueExpression "AND" ValueExpression) +// | ValueExpression "IN" "(" Expression ("," Expression)* ")" +// | ValueExpression +// ValueExpression → Operand +// +// Operand grammar follows below + +// Expression represents a logical disjunction of clauses +type Expression struct { + And []*AndCondition `parser:"@@ ( \"OR\" @@ )*"` +} + +// AndCondition represents logical conjunction of clauses +type AndCondition struct { + Condition []*Condition `parser:"@@ ( \"AND\" @@ )*"` +} + +// Condition represents a negation or a condition operand +type Condition struct { + Operand *ConditionOperand `parser:" @@"` + Not *Condition `parser:"| \"NOT\" @@"` +} + +// ConditionOperand is a operand followed by an an optional operation +// expression +type ConditionOperand struct { + Operand *Operand `parser:"@@"` + ConditionRHS *ConditionRHS `parser:"@@?"` +} + +// ConditionRHS represents the right-hand-side of Compare, Between, In +// or Like expressions. +type ConditionRHS struct { + Compare *Compare `parser:" @@"` + Between *Between `parser:"| @@"` + In *In `parser:"| \"IN\" \"(\" @@ \")\""` + Like *Like `parser:"| @@"` +} + +// Compare represents the RHS of a comparison expression +type Compare struct { + Operator string `parser:"@( \"<>\" | \"<=\" | \">=\" | \"=\" | \"<\" | \">\" | \"!=\" )"` + Operand *Operand `parser:" @@"` +} + +// Like represents the RHS of a LIKE expression +type Like struct { + Not bool `parser:" @\"NOT\"? "` + Pattern *Operand `parser:" \"LIKE\" @@ "` + EscapeChar *Operand `parser:" (\"ESCAPE\" @@)? "` +} + +// Between represents the RHS of a BETWEEN expression +type Between struct { + Not bool `parser:" @\"NOT\"? "` + Start *Operand `parser:" \"BETWEEN\" @@ "` + End *Operand `parser:" \"AND\" @@ "` +} + +// In represents the RHS of an IN expression +type In struct { + Expressions []*Expression `parser:"@@ ( \",\" @@ )*"` +} + +// Grammar for Operand: +// +// operand → multOp ( ("-" | "+") multOp )* +// multOp → unary ( ("/" | "*" | "%") unary )* +// unary → "-" unary | primary +// primary → Value | Variable | "(" expression ")" +// + +// An Operand is a single term followed by an optional sequence of +// terms separated by +/- +type Operand struct { + Left *MultOp `parser:"@@"` + Right []*OpFactor `parser:"(@@)*"` +} + +// OpFactor represents the right-side of a +/- operation. +type OpFactor struct { + Op string `parser:"@(\"+\" | \"-\")"` + Right *MultOp `parser:"@@"` +} + +// MultOp represents a single term followed by an optional sequence of +// terms separated by *, / or % operators. +type MultOp struct { + Left *UnaryTerm `parser:"@@"` + Right []*OpUnaryTerm `parser:"(@@)*"` +} + +// OpUnaryTerm represents the right side of *, / or % binary operations. +type OpUnaryTerm struct { + Op string `parser:"@(\"*\" | \"/\" | \"%\")"` + Right *UnaryTerm `parser:"@@"` +} + +// UnaryTerm represents a single negated term or a primary term +type UnaryTerm struct { + Negated *NegatedTerm `parser:" @@"` + Primary *PrimaryTerm `parser:"| @@"` +} + +// NegatedTerm has a leading minus sign. +type NegatedTerm struct { + Term *PrimaryTerm `parser:"\"-\" @@"` +} + +// PrimaryTerm represents a Value, Path expression, a Sub-expression +// or a function call. +type PrimaryTerm struct { + Value *LitValue `parser:" @@"` + JPathExpr *JSONPath `parser:"| @@"` + SubExpression *Expression `parser:"| \"(\" @@ \")\""` + // Include function expressions here. + FuncCall *FuncExpr `parser:"| @@"` +} + +// FuncExpr represents a function call +type FuncExpr struct { + SFunc *SimpleArgFunc `parser:" @@"` + Count *CountFunc `parser:"| @@"` + Cast *CastFunc `parser:"| @@"` + Substring *SubstringFunc `parser:"| @@"` + Extract *ExtractFunc `parser:"| @@"` + Trim *TrimFunc `parser:"| @@"` + + // Used during evaluation for aggregation funcs + aggregate *aggVal +} + +// SimpleArgFunc represents functions with simple expression +// arguments. +type SimpleArgFunc struct { + FunctionName string `parser:" @(\"AVG\" | \"MAX\" | \"MIN\" | \"SUM\" | \"COALESCE\" | \"NULLIF\" | \"DATE_ADD\" | \"DATE_DIFF\" | \"TO_STRING\" | \"TO_TIMESTAMP\" | \"UTCNOW\" | \"CHAR_LENGTH\" | \"CHARACTER_LENGTH\" | \"LOWER\" | \"UPPER\") "` + + ArgsList []*Expression `parser:"\"(\" (@@ (\",\" @@)*)?\")\""` +} + +// CountFunc represents the COUNT sql function +type CountFunc struct { + StarArg bool `parser:" \"COUNT\" \"(\" ( @\"*\"?"` + ExprArg *Expression `parser:" @@? )! \")\""` +} + +// CastFunc represents CAST sql function +type CastFunc struct { + Expr *Expression `parser:" \"CAST\" \"(\" @@ "` + CastType string `parser:" \"AS\" @(\"BOOL\" | \"INT\" | \"INTEGER\" | \"STRING\" | \"FLOAT\" | \"DECIMAL\" | \"NUMERIC\" | \"TIMESTAMP\") \")\" "` +} + +// SubstringFunc represents SUBSTRING sql function +type SubstringFunc struct { + Expr *PrimaryTerm `parser:" \"SUBSTRING\" \"(\" @@ "` + From *Operand `parser:" ( \"FROM\" @@ "` + For *Operand `parser:" (\"FOR\" @@)? \")\" "` + Arg2 *Operand `parser:" | \",\" @@ "` + Arg3 *Operand `parser:" (\",\" @@)? \")\" )"` +} + +// ExtractFunc represents EXTRACT sql function +type ExtractFunc struct { + Timeword string `parser:" \"EXTRACT\" \"(\" @( \"YEAR\":Timeword | \"MONTH\":Timeword | \"DAY\":Timeword | \"HOUR\":Timeword | \"MINUTE\":Timeword | \"SECOND\":Timeword | \"TIMEZONE_HOUR\":Timeword | \"TIMEZONE_MINUTE\":Timeword ) "` + From *PrimaryTerm `parser:" \"FROM\" @@ \")\" "` +} + +// TrimFunc represents TRIM sql function +type TrimFunc struct { + TrimWhere *string `parser:" \"TRIM\" \"(\" ( @( \"LEADING\" | \"TRAILING\" | \"BOTH\" ) "` + TrimChars *PrimaryTerm `parser:" @@? "` + TrimFrom *PrimaryTerm `parser:" \"FROM\" )? @@ \")\" "` +} + +// LitValue represents a literal value parsed from the sql +type LitValue struct { + Number *float64 `parser:"( @Number"` + String *LiteralString `parser:" | @LitString"` + Boolean *Boolean `parser:" | @(\"TRUE\" | \"FALSE\")"` + Null bool `parser:" | @\"NULL\")"` +} + +// Identifier represents a parsed identifier +type Identifier struct { + Unquoted *string `parser:" @Ident"` + Quoted *QuotedIdentifier `parser:"| @QuotIdent"` +} + +var ( + sqlLexer = lexer.Must(lexer.Regexp(`(\s+)` + + `|(?P(?i)\b(?:YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|TIMEZONE_HOUR|TIMEZONE_MINUTE)\b)` + + `|(?P(?i)\b(?:SELECT|FROM|TOP|DISTINCT|ALL|WHERE|GROUP|BY|HAVING|UNION|MINUS|EXCEPT|INTERSECT|ORDER|LIMIT|OFFSET|TRUE|FALSE|NULL|IS|NOT|ANY|SOME|BETWEEN|AND|OR|LIKE|ESCAPE|AS|IN|BOOL|INT|INTEGER|STRING|FLOAT|DECIMAL|NUMERIC|TIMESTAMP|AVG|COUNT|MAX|MIN|SUM|COALESCE|NULLIF|CAST|DATE_ADD|DATE_DIFF|EXTRACT|TO_STRING|TO_TIMESTAMP|UTCNOW|CHAR_LENGTH|CHARACTER_LENGTH|LOWER|SUBSTRING|TRIM|UPPER|LEADING|TRAILING|BOTH|FOR)\b)` + + `|(?P[a-zA-Z_][a-zA-Z0-9_]*)` + + `|(?P"([^"]*("")?)*")` + + `|(?P\d*\.?\d+([eE][-+]?\d+)?)` + + `|(?P'([^']*('')?)*')` + + `|(?P<>|!=|<=|>=|\.\*|\[\*\]|[-+*/%,.()=<>\[\]])`, + )) + + // SQLParser is used to parse SQL statements + SQLParser = participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + participle.CaseInsensitive("Timeword"), + ) +) diff --git a/pkg/s3select/sql/parser_test.go b/pkg/s3select/sql/parser_test.go new file mode 100644 index 000000000..d71102673 --- /dev/null +++ b/pkg/s3select/sql/parser_test.go @@ -0,0 +1,383 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "bytes" + "testing" + + "github.com/alecthomas/participle" + "github.com/alecthomas/participle/lexer" +) + +func TestJSONPathElement(t *testing.T) { + p := participle.MustBuild( + &JSONPathElement{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + j := JSONPathElement{} + cases := []string{ + // Key + "['name']", ".name", `."name"`, + + // Index + "[2]", "[0]", "[100]", + + // Object wilcard + ".*", + + // array wildcard + "[*]", + } + for i, tc := range cases { + err := p.ParseString(tc, &j) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + // repr.Println(j, repr.Indent(" "), repr.OmitEmpty(true)) + } +} + +func TestJSONPath(t *testing.T) { + p := participle.MustBuild( + &JSONPath{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + j := JSONPath{} + cases := []string{ + "S3Object", + "S3Object.id", + "S3Object.book.title", + "S3Object.id[1]", + "S3Object.id['abc']", + "S3Object.id['ab']", + "S3Object.words.*.id", + "S3Object.words.name[*].val", + "S3Object.words.name[*].val[*]", + "S3Object.words.name[*].val.*", + } + for i, tc := range cases { + err := p.ParseString(tc, &j) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + // repr.Println(j, repr.Indent(" "), repr.OmitEmpty(true)) + } + +} + +func TestIdentifierParsing(t *testing.T) { + p := participle.MustBuild( + &Identifier{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + id := Identifier{} + validCases := []string{ + "a", + "_a", + "abc_a", + "a2", + `"abc"`, + `"abc\a""ac"`, + } + for i, tc := range validCases { + err := p.ParseString(tc, &id) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + // repr.Println(id, repr.Indent(" "), repr.OmitEmpty(true)) + } + + invalidCases := []string{ + "+a", + "-a", + "1a", + `"ab`, + `abc"`, + `aa""a`, + `"a"a"`, + } + for i, tc := range invalidCases { + err := p.ParseString(tc, &id) + if err == nil { + t.Fatalf("%d: %v", i, err) + } + // fmt.Println(tc, err) + } +} + +func TestLiteralStringParsing(t *testing.T) { + var k ObjectKey + p := participle.MustBuild( + &ObjectKey{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + validCases := []string{ + "['abc']", + "['ab''c']", + "['a''b''c']", + "['abc-x_1##@(*&(#*))/\\']", + } + for i, tc := range validCases { + err := p.ParseString(tc, &k) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + if string(*k.Lit) == "" { + t.Fatalf("Incorrect parse %#v", k) + } + // repr.Println(k, repr.Indent(" "), repr.OmitEmpty(true)) + } + + invalidCases := []string{ + "['abc'']", + "['-abc'sc']", + "[abc']", + "['ac]", + } + for i, tc := range invalidCases { + err := p.ParseString(tc, &k) + if err == nil { + t.Fatalf("%d: %v", i, err) + } + // fmt.Println(tc, err) + } +} + +func TestFunctionParsing(t *testing.T) { + var fex FuncExpr + p := participle.MustBuild( + &FuncExpr{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + participle.CaseInsensitive("Timeword"), + ) + + validCases := []string{ + "count(*)", + "sum(2 + s.id)", + "sum(t)", + "avg(s.id[1])", + "coalesce(s.id[1], 2, 2 + 3)", + + "cast(s as string)", + "cast(s AS INT)", + "cast(s as DECIMAL)", + "extract(YEAR from '2018-01-09')", + "extract(month from '2018-01-09')", + + "extract(hour from '2018-01-09')", + "extract(day from '2018-01-09')", + "substring('abcd' from 2 for 2)", + "substring('abcd' from 2)", + "substring('abcd' , 2 , 2)", + + "substring('abcd' , 22 )", + "trim(' aab ')", + "trim(leading from ' aab ')", + "trim(trailing from ' aab ')", + "trim(both from ' aab ')", + + "trim(both '12' from ' aab ')", + "trim(leading '12' from ' aab ')", + "trim(trailing '12' from ' aab ')", + "count(23)", + } + for i, tc := range validCases { + err := p.ParseString(tc, &fex) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + // repr.Println(fex, repr.Indent(" "), repr.OmitEmpty(true)) + } +} + +func TestSqlLexer(t *testing.T) { + // s := bytes.NewBuffer([]byte("s.['name'].*.[*].abc.[\"abc\"]")) + s := bytes.NewBuffer([]byte("S3Object.words.*.id")) + // s := bytes.NewBuffer([]byte("COUNT(Id)")) + lex, err := sqlLexer.Lex(s) + if err != nil { + t.Fatal(err) + } + tokens, err := lexer.ConsumeAll(lex) + if err != nil { + t.Fatal(err) + } + // for i, t := range tokens { + // fmt.Printf("%d: %#v\n", i, t) + // } + if len(tokens) != 7 { + t.Fatalf("Expected 7 got %d", len(tokens)) + } +} + +func TestSelectWhere(t *testing.T) { + p := participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + s := Select{} + cases := []string{ + "select * from s3object", + "select a, b from s3object s", + "select a, b from s3object as s", + "select a, b from s3object as s where a = 1", + "select a, b from s3object s where a = 1", + "select a, b from s3object where a = 1", + } + for i, tc := range cases { + err := p.ParseString(tc, &s) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + + // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) + } +} + +func TestLikeClause(t *testing.T) { + p := participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + s := Select{} + cases := []string{ + `select * from s3object where Name like 'abcd'`, + `select Name like 'abc' from s3object`, + `select * from s3object where Name not like 'abc'`, + `select * from s3object where Name like 'abc' escape 't'`, + `select * from s3object where Name like 'a\%' escape '?'`, + `select * from s3object where Name not like 'abc\' escape '?'`, + `select * from s3object where Name like 'a\%' escape LOWER('?')`, + `select * from s3object where Name not like LOWER('Bc\') escape '?'`, + } + for i, tc := range cases { + err := p.ParseString(tc, &s) + if err != nil { + t.Errorf("%d: %v", i, err) + } + } +} + +func TestBetweenClause(t *testing.T) { + p := participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + s := Select{} + cases := []string{ + `select * from s3object where Id between 1 and 2`, + `select * from s3object where Id between 1 and 2 and name = 'Ab'`, + `select * from s3object where Id not between 1 and 2`, + `select * from s3object where Id not between 1 and 2 and name = 'Bc'`, + } + for i, tc := range cases { + err := p.ParseString(tc, &s) + if err != nil { + t.Errorf("%d: %v", i, err) + } + } +} + +func TestFromClauseJSONPath(t *testing.T) { + p := participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + s := Select{} + cases := []string{ + "select * from s3object", + "select * from s3object[*].name", + "select * from s3object[*].books[*]", + "select * from s3object[*].books[*].name", + "select * from s3object where name > 2", + "select * from s3object[*].name where name > 2", + "select * from s3object[*].books[*] where name > 2", + "select * from s3object[*].books[*].name where name > 2", + "select * from s3object[*].books[*] s", + "select * from s3object[*].books[*].name as s", + "select * from s3object s where name > 2", + "select * from s3object[*].name as s where name > 2", + } + for i, tc := range cases { + err := p.ParseString(tc, &s) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + + // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) + } + +} + +func TestSelectParsing(t *testing.T) { + p := participle.MustBuild( + &Select{}, + participle.Lexer(sqlLexer), + participle.CaseInsensitive("Keyword"), + ) + + s := Select{} + cases := []string{ + "select * from s3object where name > 2 or value > 1 or word > 2", + "select s.word.id + 2 from s3object s", + "select 1-2-3 from s3object s limit 1", + } + for i, tc := range cases { + err := p.ParseString(tc, &s) + if err != nil { + t.Fatalf("%d: %v", i, err) + } + + // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) + } +} + +func TestSqlLexerArithOps(t *testing.T) { + s := bytes.NewBuffer([]byte("year from select month hour distinct")) + lex, err := sqlLexer.Lex(s) + if err != nil { + t.Fatal(err) + } + tokens, err := lexer.ConsumeAll(lex) + if err != nil { + t.Fatal(err) + } + if len(tokens) != 7 { + t.Errorf("Expected 7 got %d", len(tokens)) + } + // for i, t := range tokens { + // fmt.Printf("%d: %#v\n", i, t) + // } +} diff --git a/pkg/s3select/sql/sql.go b/pkg/s3select/sql/sql.go deleted file mode 100644 index 11b44b357..000000000 --- a/pkg/s3select/sql/sql.go +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -import ( - "fmt" - "strings" - - "github.com/xwb1989/sqlparser" -) - -func getColumnName(colName *sqlparser.ColName) string { - columnName := colName.Qualifier.Name.String() - if qualifier := colName.Qualifier.Qualifier.String(); qualifier != "" { - columnName = qualifier + "." + columnName - } - - if columnName == "" { - columnName = colName.Name.String() - } else { - columnName = columnName + "." + colName.Name.String() - } - - return columnName -} - -func newLiteralExpr(parserExpr sqlparser.Expr, tableAlias string) (Expr, error) { - switch parserExpr.(type) { - case *sqlparser.NullVal: - return newValueExpr(NewNull()), nil - case sqlparser.BoolVal: - return newValueExpr(NewBool((bool(parserExpr.(sqlparser.BoolVal))))), nil - case *sqlparser.SQLVal: - sqlValue := parserExpr.(*sqlparser.SQLVal) - value, err := NewValue(sqlValue) - if err != nil { - return nil, err - } - return newValueExpr(value), nil - case *sqlparser.ColName: - columnName := getColumnName(parserExpr.(*sqlparser.ColName)) - if tableAlias != "" { - if !strings.HasPrefix(columnName, tableAlias+".") { - err := fmt.Errorf("column name %v does not start with table alias %v", columnName, tableAlias) - return nil, errInvalidKeyPath(err) - } - columnName = strings.TrimPrefix(columnName, tableAlias+".") - } - - return newColumnExpr(columnName), nil - case sqlparser.ValTuple: - var valueType Type - var values []*Value - for i, valExpr := range parserExpr.(sqlparser.ValTuple) { - sqlVal, ok := valExpr.(*sqlparser.SQLVal) - if !ok { - return nil, errParseInvalidTypeParam(fmt.Errorf("value %v in Tuple should be primitive value", i+1)) - } - - val, err := NewValue(sqlVal) - if err != nil { - return nil, err - } - - if i == 0 { - valueType = val.Type() - } else if valueType != val.Type() { - return nil, errParseInvalidTypeParam(fmt.Errorf("mixed value type is not allowed in Tuple")) - } - - values = append(values, val) - } - - return newValueExpr(NewArray(values)), nil - } - - return nil, nil -} - -func isExprToComparisonExpr(parserExpr *sqlparser.IsExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Expr, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newComparisonExpr(ComparisonOperator(parserExpr.Operator), leftExpr) - if err != nil { - return nil, err - } - - if !leftExpr.Type().isBase() { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func rangeCondToComparisonFunc(parserExpr *sqlparser.RangeCond, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Left, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - fromExpr, err := newExpr(parserExpr.From, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - toExpr, err := newExpr(parserExpr.To, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newComparisonExpr(ComparisonOperator(parserExpr.Operator), leftExpr, fromExpr, toExpr) - if err != nil { - return nil, err - } - - if !leftExpr.Type().isBase() || !fromExpr.Type().isBase() || !toExpr.Type().isBase() { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func toComparisonExpr(parserExpr *sqlparser.ComparisonExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Left, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - rightExpr, err := newExpr(parserExpr.Right, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newComparisonExpr(ComparisonOperator(parserExpr.Operator), leftExpr, rightExpr) - if err != nil { - return nil, err - } - - if !leftExpr.Type().isBase() || !rightExpr.Type().isBase() { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func toArithExpr(parserExpr *sqlparser.BinaryExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Left, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - rightExpr, err := newExpr(parserExpr.Right, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newArithExpr(ArithOperator(parserExpr.Operator), leftExpr, rightExpr) - if err != nil { - return nil, err - } - - if !leftExpr.Type().isBase() || !rightExpr.Type().isBase() { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func toFuncExpr(parserExpr *sqlparser.FuncExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - funcName := strings.ToUpper(parserExpr.Name.String()) - if !isSelectExpr && isAggregateFuncName(funcName) { - return nil, errUnsupportedSQLOperation(fmt.Errorf("%v() must be used in select expression", funcName)) - } - funcs, aggregatedExprFound, err := newSelectExprs(parserExpr.Exprs, tableAlias) - if err != nil { - return nil, err - } - - if aggregatedExprFound { - return nil, errIncorrectSQLFunctionArgumentType(fmt.Errorf("%v(): aggregated expression must not be used as argument", funcName)) - } - - return newFuncExpr(FuncName(funcName), funcs...) -} - -func toAndExpr(parserExpr *sqlparser.AndExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Left, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - rightExpr, err := newExpr(parserExpr.Right, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newAndExpr(leftExpr, rightExpr) - if err != nil { - return nil, err - } - - if leftExpr.Type() != Bool || rightExpr.Type() != Bool { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func toOrExpr(parserExpr *sqlparser.OrExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - leftExpr, err := newExpr(parserExpr.Left, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - rightExpr, err := newExpr(parserExpr.Right, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newOrExpr(leftExpr, rightExpr) - if err != nil { - return nil, err - } - - if leftExpr.Type() != Bool || rightExpr.Type() != Bool { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func toNotExpr(parserExpr *sqlparser.NotExpr, tableAlias string, isSelectExpr bool) (Expr, error) { - rightExpr, err := newExpr(parserExpr.Expr, tableAlias, isSelectExpr) - if err != nil { - return nil, err - } - - f, err := newNotExpr(rightExpr) - if err != nil { - return nil, err - } - - if rightExpr.Type() != Bool { - return f, nil - } - - value, err := f.Eval(nil) - if err != nil { - return nil, err - } - - return newValueExpr(value), nil -} - -func newExpr(parserExpr sqlparser.Expr, tableAlias string, isSelectExpr bool) (Expr, error) { - f, err := newLiteralExpr(parserExpr, tableAlias) - if err != nil { - return nil, err - } - - if f != nil { - return f, nil - } - - switch parserExpr.(type) { - case *sqlparser.ParenExpr: - return newExpr(parserExpr.(*sqlparser.ParenExpr).Expr, tableAlias, isSelectExpr) - case *sqlparser.IsExpr: - return isExprToComparisonExpr(parserExpr.(*sqlparser.IsExpr), tableAlias, isSelectExpr) - case *sqlparser.RangeCond: - return rangeCondToComparisonFunc(parserExpr.(*sqlparser.RangeCond), tableAlias, isSelectExpr) - case *sqlparser.ComparisonExpr: - return toComparisonExpr(parserExpr.(*sqlparser.ComparisonExpr), tableAlias, isSelectExpr) - case *sqlparser.BinaryExpr: - return toArithExpr(parserExpr.(*sqlparser.BinaryExpr), tableAlias, isSelectExpr) - case *sqlparser.FuncExpr: - return toFuncExpr(parserExpr.(*sqlparser.FuncExpr), tableAlias, isSelectExpr) - case *sqlparser.AndExpr: - return toAndExpr(parserExpr.(*sqlparser.AndExpr), tableAlias, isSelectExpr) - case *sqlparser.OrExpr: - return toOrExpr(parserExpr.(*sqlparser.OrExpr), tableAlias, isSelectExpr) - case *sqlparser.NotExpr: - return toNotExpr(parserExpr.(*sqlparser.NotExpr), tableAlias, isSelectExpr) - } - - return nil, errParseUnsupportedSyntax(fmt.Errorf("unknown expression type %T; %v", parserExpr, parserExpr)) -} - -func newSelectExprs(parserSelectExprs []sqlparser.SelectExpr, tableAlias string) ([]Expr, bool, error) { - var funcs []Expr - starExprFound := false - aggregatedExprFound := false - - for _, selectExpr := range parserSelectExprs { - switch selectExpr.(type) { - case *sqlparser.AliasedExpr: - if starExprFound { - return nil, false, errParseAsteriskIsNotAloneInSelectList(nil) - } - - aliasedExpr := selectExpr.(*sqlparser.AliasedExpr) - f, err := newExpr(aliasedExpr.Expr, tableAlias, true) - if err != nil { - return nil, false, err - } - - if f.Type() == aggregateFunction { - if !aggregatedExprFound { - aggregatedExprFound = true - if len(funcs) > 0 { - return nil, false, errParseUnsupportedSyntax(fmt.Errorf("expression must not mixed with aggregated expression")) - } - } - } else if aggregatedExprFound { - return nil, false, errParseUnsupportedSyntax(fmt.Errorf("expression must not mixed with aggregated expression")) - } - - alias := aliasedExpr.As.String() - if alias != "" { - f = newAliasExpr(alias, f) - } - - funcs = append(funcs, f) - case *sqlparser.StarExpr: - if starExprFound { - err := fmt.Errorf("only single star expression allowed") - return nil, false, errParseInvalidContextForWildcardInSelectList(err) - } - starExprFound = true - funcs = append(funcs, newStarExpr()) - default: - return nil, false, errParseUnsupportedSyntax(fmt.Errorf("unknown select expression %v", selectExpr)) - } - } - - return funcs, aggregatedExprFound, nil -} - -// Select - SQL Select statement. -type Select struct { - tableName string - tableAlias string - selectExprs []Expr - aggregatedExprFound bool - whereExpr Expr -} - -// TableAlias - returns table alias name. -func (statement *Select) TableAlias() string { - return statement.tableAlias -} - -// IsSelectAll - returns whether '*' is used in select expression or not. -func (statement *Select) IsSelectAll() bool { - if len(statement.selectExprs) == 1 { - _, ok := statement.selectExprs[0].(*starExpr) - return ok - } - - return false -} - -// IsAggregated - returns whether aggregated functions are used in select expression or not. -func (statement *Select) IsAggregated() bool { - return statement.aggregatedExprFound -} - -// AggregateResult - returns aggregate result as record. -func (statement *Select) AggregateResult(output Record) error { - if !statement.aggregatedExprFound { - return nil - } - - for i, expr := range statement.selectExprs { - value, err := expr.AggregateValue() - if err != nil { - return err - } - if value == nil { - return errInternalError(fmt.Errorf("%v returns for AggregateValue()", expr)) - } - - name := fmt.Sprintf("_%v", i+1) - if _, ok := expr.(*aliasExpr); ok { - name = expr.(*aliasExpr).alias - } - - if err = output.Set(name, value); err != nil { - return errInternalError(fmt.Errorf("error occurred to store value %v for %v; %v", value, name, err)) - } - } - - return nil -} - -// Eval - evaluates this Select expressions for given record. -func (statement *Select) Eval(input, output Record) (Record, error) { - if statement.whereExpr != nil { - value, err := statement.whereExpr.Eval(input) - if err != nil { - return nil, err - } - - if value == nil || value.valueType != Bool { - err = fmt.Errorf("WHERE expression %v returns invalid bool value %v", statement.whereExpr, value) - return nil, errInternalError(err) - } - - if !value.BoolValue() { - return nil, nil - } - } - - // Call selectExprs - for i, expr := range statement.selectExprs { - value, err := expr.Eval(input) - if err != nil { - return nil, err - } - - if statement.aggregatedExprFound { - continue - } - - name := fmt.Sprintf("_%v", i+1) - switch expr.(type) { - case *starExpr: - return value.recordValue(), nil - case *aliasExpr: - name = expr.(*aliasExpr).alias - case *columnExpr: - name = expr.(*columnExpr).name - } - - if err = output.Set(name, value); err != nil { - return nil, errInternalError(fmt.Errorf("error occurred to store value %v for %v; %v", value, name, err)) - } - } - - return output, nil -} - -// NewSelect - creates new Select by parsing sql. -func NewSelect(sql string) (*Select, error) { - stmt, err := sqlparser.Parse(sql) - if err != nil { - return nil, errUnsupportedSQLStructure(err) - } - - selectStmt, ok := stmt.(*sqlparser.Select) - if !ok { - return nil, errParseUnsupportedSelect(fmt.Errorf("unsupported SQL statement %v", sql)) - } - - var tableName, tableAlias string - for _, fromExpr := range selectStmt.From { - tableExpr := fromExpr.(*sqlparser.AliasedTableExpr) - tableName = tableExpr.Expr.(sqlparser.TableName).Name.String() - tableAlias = tableExpr.As.String() - } - - selectExprs, aggregatedExprFound, err := newSelectExprs(selectStmt.SelectExprs, tableAlias) - if err != nil { - return nil, err - } - - var whereExpr Expr - if selectStmt.Where != nil { - whereExpr, err = newExpr(selectStmt.Where.Expr, tableAlias, false) - if err != nil { - return nil, err - } - } - - return &Select{ - tableName: tableName, - tableAlias: tableAlias, - selectExprs: selectExprs, - aggregatedExprFound: aggregatedExprFound, - whereExpr: whereExpr, - }, nil -} diff --git a/pkg/s3select/sql/statement.go b/pkg/s3select/sql/statement.go new file mode 100644 index 000000000..35b93dbd7 --- /dev/null +++ b/pkg/s3select/sql/statement.go @@ -0,0 +1,202 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "fmt" + "strings" +) + +var ( + errBadLimitSpecified = errors.New("Limit value must be a positive integer") +) + +// SelectStatement is the top level parsed and analyzed structure +type SelectStatement struct { + selectAST *Select + + // Analysis result of the statement + selectQProp qProp + + // Result of parsing the limit clause if one is present + // (otherwise -1) + limitValue int64 + + // Count of rows that have been output. + outputCount int64 +} + +// ParseSelectStatement - parses a select query from the given string +// and analyzes it. +func ParseSelectStatement(s string) (stmt SelectStatement, err error) { + var selectAST Select + err = SQLParser.ParseString(s, &selectAST) + if err != nil { + err = errQueryParseFailure(err) + return + } + stmt.selectAST = &selectAST + + // Check the parsed limit value + stmt.limitValue, err = parseLimit(selectAST.Limit) + if err != nil { + err = errQueryAnalysisFailure(err) + return + } + + // Analyze where clause + if selectAST.Where != nil { + whereQProp := selectAST.Where.analyze(&selectAST) + if whereQProp.err != nil { + err = errQueryAnalysisFailure(fmt.Errorf("Where clause error: %v", whereQProp.err)) + return + } + + if whereQProp.isAggregation { + err = errQueryAnalysisFailure(errors.New("WHERE clause cannot have an aggregation")) + return + } + } + + // Validate table name + tableString := strings.ToLower(selectAST.From.Table.String()) + if !strings.HasPrefix(tableString, "s3object.") && tableString != "s3object" { + err = errBadTableName(errors.New("Table name must be s3object")) + return + } + + // Analyze main select expression + stmt.selectQProp = selectAST.Expression.analyze(&selectAST) + err = stmt.selectQProp.err + if err != nil { + fmt.Println("Got Analysis err:", err) + err = errQueryAnalysisFailure(err) + } + return +} + +func parseLimit(v *LitValue) (int64, error) { + switch { + case v == nil: + return -1, nil + case v.Number == nil: + return -1, errBadLimitSpecified + default: + r := int64(*v.Number) + if r < 0 { + return -1, errBadLimitSpecified + } + return r, nil + } +} + +// IsAggregated returns if the statement involves SQL aggregation +func (e *SelectStatement) IsAggregated() bool { + return e.selectQProp.isAggregation +} + +// AggregateResult - returns the aggregated result after all input +// records have been processed. Applies only to aggregation queries. +func (e *SelectStatement) AggregateResult(output Record) error { + for i, expr := range e.selectAST.Expression.Expressions { + v, err := expr.evalNode(nil) + if err != nil { + return err + } + output.Set(fmt.Sprintf("_%d", i+1), v) + } + return nil +} + +// AggregateRow - aggregates the input record. Applies only to +// aggregation queries. +func (e *SelectStatement) AggregateRow(input Record) error { + for _, expr := range e.selectAST.Expression.Expressions { + err := expr.aggregateRow(input) + if err != nil { + return err + } + } + return nil +} + +// Eval - evaluates the Select statement for the given record. It +// applies only to non-aggregation queries. +func (e *SelectStatement) Eval(input, output Record) (Record, error) { + if whereExpr := e.selectAST.Where; whereExpr != nil { + value, err := whereExpr.evalNode(input) + if err != nil { + return nil, err + } + + b, ok := value.ToBool() + if !ok { + err = fmt.Errorf("WHERE expression did not return bool") + return nil, err + } + + if !b { + // Where clause is not satisfied by the row + return nil, nil + } + } + + if e.selectAST.Expression.All { + // Return the input record for `SELECT * FROM + // .. WHERE ..` + + // Update count of records output. + if e.limitValue > -1 { + e.outputCount++ + } + + return input, nil + } + + for i, expr := range e.selectAST.Expression.Expressions { + v, err := expr.evalNode(input) + if err != nil { + return nil, err + } + + // Pick output column names + if expr.As != "" { + output.Set(expr.As, v) + } else if comp, ok := getLastKeypathComponent(expr.Expression); ok { + output.Set(comp, v) + } else { + output.Set(fmt.Sprintf("_%d", i+1), v) + } + } + + // Update count of records output. + if e.limitValue > -1 { + e.outputCount++ + } + + return output, nil +} + +// LimitReached - returns true if the number of records output has +// reached the value of the `LIMIT` clause. +func (e *SelectStatement) LimitReached() bool { + if e.limitValue == -1 { + return false + } + return e.outputCount >= e.limitValue +} diff --git a/pkg/s3select/sql/stringfuncs.go b/pkg/s3select/sql/stringfuncs.go new file mode 100644 index 000000000..1ad803459 --- /dev/null +++ b/pkg/s3select/sql/stringfuncs.go @@ -0,0 +1,188 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "errors" + "strings" +) + +var ( + errMalformedEscapeSequence = errors.New("Malformed escape sequence in LIKE clause") + errInvalidTrimArg = errors.New("Trim argument is invalid - this should not happen") + errInvalidSubstringIndexLen = errors.New("Substring start index or length falls outside the string") +) + +const ( + percent rune = '%' + underscore rune = '_' + runeZero rune = 0 +) + +func evalSQLLike(text, pattern string, escape rune) (match bool, err error) { + s := []rune{} + prev := runeZero + hasLeadingPercent := false + patLen := len([]rune(pattern)) + for i, r := range pattern { + if i > 0 && prev == escape { + switch r { + case percent, escape, underscore: + s = append(s, r) + prev = r + if r == escape { + prev = runeZero + } + default: + return false, errMalformedEscapeSequence + } + continue + } + + prev = r + + var ok bool + switch r { + case percent: + if len(s) == 0 { + hasLeadingPercent = true + continue + } + + text, ok = matcher(text, string(s), hasLeadingPercent) + if !ok { + return false, nil + } + hasLeadingPercent = true + s = []rune{} + + if i == patLen-1 { + // Last pattern character is a %, so + // we are done. + return true, nil + } + + case underscore: + if len(s) == 0 { + text, ok = dropRune(text) + if !ok { + return false, nil + } + continue + } + + text, ok = matcher(text, string(s), hasLeadingPercent) + if !ok { + return false, nil + } + hasLeadingPercent = false + + text, ok = dropRune(text) + if !ok { + return false, nil + } + s = []rune{} + + case escape: + if i == patLen-1 { + return false, errMalformedEscapeSequence + } + // Otherwise do nothing. + + default: + s = append(s, r) + } + + } + if hasLeadingPercent { + return strings.HasSuffix(text, string(s)), nil + } + return string(s) == text, nil +} + +// matcher - Finds `pat` in `text`, and returns the part remainder of +// `text`, after the match. If leadingPercent is false, `pat` must be +// the prefix of `text`, otherwise it must be a substring. +func matcher(text, pat string, leadingPercent bool) (res string, match bool) { + if !leadingPercent { + res = strings.TrimPrefix(text, pat) + if len(text) == len(res) { + return "", false + } + } else { + parts := strings.SplitN(text, pat, 2) + if len(parts) == 1 { + return "", false + } + res = parts[1] + } + return res, true +} + +func dropRune(text string) (res string, ok bool) { + r := []rune(text) + if len(r) == 0 { + return "", false + } + return string(r[1:]), true +} + +func evalSQLSubstring(s string, startIdx, length int) (res string, err error) { + if startIdx <= 0 || startIdx > len(s) { + return "", errInvalidSubstringIndexLen + } + // StartIdx is 1-based in the input + startIdx-- + + rs := []rune(s) + endIdx := len(rs) + if length != -1 { + if length < 0 || startIdx+length > len(s) { + return "", errInvalidSubstringIndexLen + } + endIdx = startIdx + length + } + + return string(rs[startIdx:endIdx]), nil +} + +const ( + trimLeading = "LEADING" + trimTrailing = "TRAILING" + trimBoth = "BOTH" +) + +func evalSQLTrim(where *string, trimChars, text string) (result string, err error) { + cutSet := " " + if trimChars != "" { + cutSet = trimChars + } + + trimFunc := strings.Trim + switch { + case where == nil: + case *where == trimBoth: + case *where == trimLeading: + trimFunc = strings.TrimLeft + case *where == trimTrailing: + trimFunc = strings.TrimRight + default: + return "", errInvalidTrimArg + } + + return trimFunc(text, cutSet), nil +} diff --git a/pkg/s3select/sql/stringfuncs_test.go b/pkg/s3select/sql/stringfuncs_test.go new file mode 100644 index 000000000..8f04f0fef --- /dev/null +++ b/pkg/s3select/sql/stringfuncs_test.go @@ -0,0 +1,107 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "testing" +) + +func TestEvalSQLLike(t *testing.T) { + dropCases := []struct { + input, resultExpected string + matchExpected bool + }{ + {"", "", false}, + {"a", "", true}, + {"ab", "b", true}, + {"தமிழ்", "மிழ்", true}, + } + + for i, tc := range dropCases { + res, ok := dropRune(tc.input) + if res != tc.resultExpected || ok != tc.matchExpected { + t.Errorf("DropRune Case %d failed", i) + } + } + + matcherCases := []struct { + iText, iPat string + iHasLeadingPercent bool + resultExpected string + matchExpected bool + }{ + {"abcd", "bcd", false, "", false}, + {"abcd", "bcd", true, "", true}, + {"abcd", "abcd", false, "", true}, + {"abcd", "abcd", true, "", true}, + {"abcd", "ab", false, "cd", true}, + {"abcd", "ab", true, "cd", true}, + {"abcd", "bc", false, "", false}, + {"abcd", "bc", true, "d", true}, + } + + for i, tc := range matcherCases { + res, ok := matcher(tc.iText, tc.iPat, tc.iHasLeadingPercent) + if res != tc.resultExpected || ok != tc.matchExpected { + t.Errorf("Matcher Case %d failed", i) + } + } + + evalCases := []struct { + iText, iPat string + iEsc rune + matchExpected bool + errExpected error + }{ + {"abcd", "abc", runeZero, false, nil}, + {"abcd", "abcd", runeZero, true, nil}, + {"abcd", "abc_", runeZero, true, nil}, + {"abcd", "_bdd", runeZero, false, nil}, + {"abcd", "_b_d", runeZero, true, nil}, + + {"abcd", "____", runeZero, true, nil}, + {"abcd", "____%", runeZero, true, nil}, + {"abcd", "%____", runeZero, true, nil}, + {"abcd", "%__", runeZero, true, nil}, + {"abcd", "____", runeZero, true, nil}, + + {"", "_", runeZero, false, nil}, + {"", "%", runeZero, true, nil}, + {"abcd", "%%%%%", runeZero, true, nil}, + {"abcd", "_____", runeZero, false, nil}, + {"abcd", "%%%%%", runeZero, true, nil}, + + {"a%%d", `a\%\%d`, '\\', true, nil}, + {"a%%d", `a\%d`, '\\', false, nil}, + {`a%%\d`, `a\%\%\\d`, '\\', true, nil}, + {`a%%\`, `a\%\%\\`, '\\', true, nil}, + {`a%__%\`, `a\%\_\_\%\\`, '\\', true, nil}, + + {`a%__%\`, `a\%\_\_\%_`, '\\', true, nil}, + {`a%__%\`, `a\%\_\__`, '\\', false, nil}, + {`a%__%\`, `a\%\_\_%`, '\\', true, nil}, + {`a%__%\`, `a?%?_?_?%\`, '?', true, nil}, + } + + for i, tc := range evalCases { + // fmt.Println("Case:", i) + res, err := evalSQLLike(tc.iText, tc.iPat, tc.iEsc) + if res != tc.matchExpected || err != tc.errExpected { + t.Errorf("Eval Case %d failed: %v %v", i, res, err) + } + } +} diff --git a/pkg/s3select/sql/type.go b/pkg/s3select/sql/type.go deleted file mode 100644 index cb591ab85..000000000 --- a/pkg/s3select/sql/type.go +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2019 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sql - -// Type - value type. -type Type string - -const ( - // Null - represents NULL value type. - Null Type = "null" - - // Bool - represents boolean value type. - Bool Type = "bool" - - // Int - represents integer value type. - Int Type = "int" - - // Float - represents floating point value type. - Float Type = "float" - - // String - represents string value type. - String Type = "string" - - // Timestamp - represents time value type. - Timestamp Type = "timestamp" - - // Array - represents array of values where each value type is one of above. - Array Type = "array" - - column Type = "column" - record Type = "record" - function Type = "function" - aggregateFunction Type = "aggregatefunction" - arithmeticFunction Type = "arithmeticfunction" - comparisonFunction Type = "comparisonfunction" - logicalFunction Type = "logicalfunction" - - // Integer Type = "integer" // Same as Int - // Decimal Type = "decimal" // Same as Float - // Numeric Type = "numeric" // Same as Float -) - -func (t Type) isBase() bool { - switch t { - case Null, Bool, Int, Float, String, Timestamp: - return true - } - - return false -} - -func (t Type) isBaseKind() bool { - switch t { - case Null, Bool, Int, Float, String, Timestamp, column: - return true - } - - return false -} - -func (t Type) isNumber() bool { - switch t { - case Int, Float: - return true - } - - return false -} - -func (t Type) isNumberKind() bool { - switch t { - case Int, Float, column: - return true - } - - return false -} - -func (t Type) isIntKind() bool { - switch t { - case Int, column: - return true - } - - return false -} - -func (t Type) isBoolKind() bool { - switch t { - case Bool, column: - return true - } - - return false -} - -func (t Type) isStringKind() bool { - switch t { - case String, column: - return true - } - - return false -} diff --git a/pkg/s3select/sql/utils.go b/pkg/s3select/sql/utils.go new file mode 100644 index 000000000..0fc5ea3e5 --- /dev/null +++ b/pkg/s3select/sql/utils.go @@ -0,0 +1,87 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sql + +import ( + "fmt" + "strings" +) + +// String functions + +// String - returns the JSONPath representation +func (e *JSONPath) String() string { + parts := make([]string, len(e.PathExpr)+1) + parts[0] = e.BaseKey.String() + for i, pe := range e.PathExpr { + parts[i+1] = pe.String() + } + return strings.Join(parts, "") +} + +func (e *JSONPathElement) String() string { + switch { + case e.Key != nil: + return e.Key.String() + case e.Index != nil: + return fmt.Sprintf("[%d]", *e.Index) + case e.ObjectWildcard: + return ".*" + case e.ArrayWildcard: + return "[*]" + } + return "" +} + +// Removes double quotes in quoted identifiers +func (i *Identifier) String() string { + if i.Unquoted != nil { + return *i.Unquoted + } + return string(*i.Quoted) +} + +func (o *ObjectKey) String() string { + if o.Lit != nil { + return fmt.Sprintf("['%s']", string(*o.Lit)) + } + return fmt.Sprintf(".%s", o.ID.String()) +} + +// getLastKeypathComponent checks if the given expression is a path +// expression, and if so extracts the last dot separated component of +// the path. Otherwise it returns false. +func getLastKeypathComponent(e *Expression) (string, bool) { + if len(e.And) > 1 || + len(e.And[0].Condition) > 1 || + e.And[0].Condition[0].Not != nil || + e.And[0].Condition[0].Operand.ConditionRHS != nil { + return "", false + } + + operand := e.And[0].Condition[0].Operand.Operand + if operand.Right != nil || + operand.Left.Right != nil || + operand.Left.Left.Negated != nil || + operand.Left.Left.Primary.JPathExpr == nil { + return "", false + } + + keypath := operand.Left.Left.Primary.JPathExpr.String() + ps := strings.Split(keypath, ".") + return ps[len(ps)-1], true +} diff --git a/pkg/s3select/sql/value.go b/pkg/s3select/sql/value.go index 5b47f420b..49420c00d 100644 --- a/pkg/s3select/sql/value.go +++ b/pkg/s3select/sql/value.go @@ -17,220 +17,710 @@ package sql import ( - "encoding/json" + "errors" "fmt" + "math" "strconv" "strings" - "time" - - "github.com/xwb1989/sqlparser" ) -// Value - represents any primitive value of bool, int, float, string and time. +var ( + errArithMismatchedTypes = errors.New("cannot perform arithmetic on mismatched types") + errArithInvalidOperator = errors.New("invalid arithmetic operator") + errArithDivideByZero = errors.New("cannot divide by 0") + + errCmpMismatchedTypes = errors.New("cannot compare values of different types") + errCmpInvalidBoolOperator = errors.New("invalid comparison operator for boolean arguments") +) + +// vType represents the concrete type of a `Value` +type vType int + +// Valid values for Type +const ( + typeNull vType = iota + 1 + typeBool + typeString + + // 64-bit signed integer + typeInt + + // 64-bit floating point + typeFloat + + // This type refers to untyped values, e.g. as read from CSV + typeBytes +) + +// Value represents a value of restricted type reduced from an +// expression represented by an ASTNode. Only one of the fields is +// non-nil. +// +// In cases where we are fetching data from a data source (like csv), +// the type may not be determined yet. In these cases, a byte-slice is +// used. type Value struct { - value interface{} - valueType Type + value interface{} + vType vType } -// String - represents value as string. -func (value *Value) String() string { - if value.value == nil { - if value.valueType == Null { - return "NULL" - } - - return "" +// GetTypeString returns a string representation for vType +func (v *Value) GetTypeString() string { + switch v.vType { + case typeNull: + return "NULL" + case typeBool: + return "BOOL" + case typeString: + return "STRING" + case typeInt: + return "INT" + case typeFloat: + return "FLOAT" + case typeBytes: + return "BYTES" } - - switch value.valueType { - case String: - return fmt.Sprintf("'%v'", value.value) - case Array: - var valueStrings []string - for _, v := range value.value.([]*Value) { - valueStrings = append(valueStrings, fmt.Sprintf("%v", v)) - } - return fmt.Sprintf("(%v)", strings.Join(valueStrings, ",")) - } - - return fmt.Sprintf("%v", value.value) + return "--" } -// CSVString - encodes to CSV string. -func (value *Value) CSVString() string { - if value.valueType == Null { +// Repr returns a string representation of value. +func (v *Value) Repr() string { + switch v.vType { + case typeNull: + return ":NULL" + case typeBool, typeInt, typeFloat: + return fmt.Sprintf("%v:%s", v.value, v.GetTypeString()) + case typeString: + return fmt.Sprintf("\"%s\":%s", v.value.(string), v.GetTypeString()) + case typeBytes: + return fmt.Sprintf("\"%s\":BYTES", string(v.value.([]byte))) + default: + return fmt.Sprintf("%v:INVALID", v.value) + } +} + +// FromFloat creates a Value from a number +func FromFloat(f float64) *Value { + return &Value{value: f, vType: typeFloat} +} + +// FromInt creates a Value from an int +func FromInt(f int64) *Value { + return &Value{value: f, vType: typeInt} +} + +// FromString creates a Value from a string +func FromString(str string) *Value { + return &Value{value: str, vType: typeString} +} + +// FromBool creates a Value from a bool +func FromBool(b bool) *Value { + return &Value{value: b, vType: typeBool} +} + +// FromNull creates a Value with Null value +func FromNull() *Value { + return &Value{vType: typeNull} +} + +// FromBytes creates a Value from a []byte +func FromBytes(b []byte) *Value { + return &Value{value: b, vType: typeBytes} +} + +// ToFloat works for int and float values +func (v *Value) ToFloat() (val float64, ok bool) { + switch v.vType { + case typeFloat: + val, ok = v.value.(float64) + case typeInt: + var i int64 + i, ok = v.value.(int64) + val = float64(i) + default: + } + return +} + +// ToInt converts value to int. +func (v *Value) ToInt() (val int64, ok bool) { + switch v.vType { + case typeInt: + val, ok = v.value.(int64) + default: + } + return +} + +// ToString converts value to string. +func (v *Value) ToString() (val string, ok bool) { + switch v.vType { + case typeString: + val, ok = v.value.(string) + default: + } + return +} + +// ToBool returns the bool value; second return value refers to if the bool +// conversion succeeded. +func (v *Value) ToBool() (val bool, ok bool) { + switch v.vType { + case typeBool: + return v.value.(bool), true + } + return false, false +} + +// ToBytes converts Value to byte-slice. +func (v *Value) ToBytes() ([]byte, bool) { + switch v.vType { + case typeBytes: + return v.value.([]byte), true + } + return nil, false +} + +// IsNull - checks if value is missing. +func (v *Value) IsNull() bool { + return v.vType == typeNull +} + +func (v *Value) isNumeric() bool { + return v.vType == typeInt || v.vType == typeFloat +} + +// setters used internally to mutate values + +func (v *Value) setInt(i int64) { + v.vType = typeInt + v.value = i +} + +func (v *Value) setFloat(f float64) { + v.vType = typeFloat + v.value = f +} + +func (v *Value) setString(s string) { + v.vType = typeString + v.value = s +} + +func (v *Value) setBool(b bool) { + v.vType = typeBool + v.value = b +} + +// CSVString - convert to string for CSV serialization +func (v *Value) CSVString() string { + switch v.vType { + case typeNull: return "" + case typeBool: + return fmt.Sprintf("%v", v.value.(bool)) + case typeString: + return fmt.Sprintf("%s", v.value.(string)) + case typeInt: + return fmt.Sprintf("%v", v.value.(int64)) + case typeFloat: + return fmt.Sprintf("%v", v.value.(float64)) + case typeBytes: + return fmt.Sprintf("%v", string(v.value.([]byte))) + default: + return "CSV serialization not implemented for this type" + } +} + +// floatToValue converts a float into int representation if needed. +func floatToValue(f float64) *Value { + intPart, fracPart := math.Modf(f) + if fracPart == 0 { + return FromInt(int64(intPart)) + } + return FromFloat(f) +} + +// Value comparison functions: we do not expose them outside the +// module. Logical operators "<", ">", ">=", "<=" work on strings and +// numbers. Equality operators "=", "!=" work on strings, +// numbers and booleans. + +// Supported comparison operators +const ( + opLt = "<" + opLte = "<=" + opGt = ">" + opGte = ">=" + opEq = "=" + opIneq = "!=" +) + +// When numeric types are compared, type promotions could happen. If +// values do not have types (e.g. when reading from CSV), for +// comparison operations, automatic type conversion happens by trying +// to check if the value is a number (first an integer, then a float), +// and falling back to string. +func (v *Value) compareOp(op string, a *Value) (res bool, err error) { + if !isValidComparisonOperator(op) { + return false, errArithInvalidOperator } - return fmt.Sprintf("%v", value.value) + // Check if type conversion/inference is needed - it is needed + // if the Value is a byte-slice. + err = inferTypesForCmp(v, a) + if err != nil { + return false, err + } + + isNumeric := v.isNumeric() && a.isNumeric() + if isNumeric { + intV, ok1i := v.ToInt() + intA, ok2i := a.ToInt() + if ok1i && ok2i { + return intCompare(op, intV, intA), nil + } + + // If both values are numeric, then at least one is + // float since we got here, so we convert. + flV, _ := v.ToFloat() + flA, _ := a.ToFloat() + return floatCompare(op, flV, flA), nil + } + + strV, ok1s := v.ToString() + strA, ok2s := a.ToString() + if ok1s && ok2s { + return stringCompare(op, strV, strA), nil + } + + boolV, ok1b := v.ToBool() + boolA, ok2b := v.ToBool() + if ok1b && ok2b { + return boolCompare(op, boolV, boolA) + } + + return false, errCmpMismatchedTypes } -// MarshalJSON - encodes to JSON data. -func (value *Value) MarshalJSON() ([]byte, error) { - return json.Marshal(value.value) +func inferTypesForCmp(a *Value, b *Value) error { + _, okA := a.ToBytes() + _, okB := b.ToBytes() + switch { + case !okA && !okB: + // Both Values already have types + return nil + + case okA && okB: + // Both Values are untyped so try the types in order: + // int, float, bool, string + + // Check for numeric inference + iA, okAi := a.bytesToInt() + iB, okBi := b.bytesToInt() + if okAi && okBi { + a.setInt(iA) + b.setInt(iB) + return nil + } + + fA, okAf := a.bytesToFloat() + fB, okBf := b.bytesToFloat() + if okAf && okBf { + a.setFloat(fA) + b.setFloat(fB) + return nil + } + + // Check if they int and float combination. + if okAi && okBf { + a.setInt(iA) + b.setFloat(fA) + return nil + } + if okBi && okAf { + a.setFloat(fA) + b.setInt(iB) + return nil + } + + // Not numeric types at this point. + + // Check for bool inference + bA, okAb := a.bytesToBool() + bB, okBb := b.bytesToBool() + if okAb && okBb { + a.setBool(bA) + b.setBool(bB) + return nil + } + + // Fallback to string + sA := a.bytesToString() + sB := b.bytesToString() + a.setString(sA) + b.setString(sB) + return nil + + case okA && !okB: + // Here a has `a` is untyped, but `b` has a fixed + // type. + switch b.vType { + case typeString: + s := a.bytesToString() + a.setString(s) + + case typeInt, typeFloat: + if iA, ok := a.bytesToInt(); ok { + a.setInt(iA) + } else if fA, ok := a.bytesToFloat(); ok { + a.setFloat(fA) + } else { + return fmt.Errorf("Could not convert %s to a number", string(a.value.([]byte))) + } + + case typeBool: + if bA, ok := a.bytesToBool(); ok { + a.setBool(bA) + } else { + return fmt.Errorf("Could not convert %s to a boolean", string(a.value.([]byte))) + } + + default: + return errCmpMismatchedTypes + } + return nil + + case !okA && okB: + // swap arguments to avoid repeating code + return inferTypesForCmp(b, a) + + default: + // Does not happen + return nil + } } -// NullValue - returns underlying null value. It panics if value is not null type. -func (value *Value) NullValue() *struct{} { - if value.valueType == Null { +// Value arithmetic functions: we do not expose them outside the +// module. All arithmetic works only on numeric values with automatic +// promotion to the "larger" type that can represent the value. TODO: +// Add support for large number arithmetic. + +// Supported arithmetic operators +const ( + opPlus = "+" + opMinus = "-" + opDivide = "/" + opMultiply = "*" + opModulo = "%" +) + +// For arithmetic operations, if both values are numeric then the +// operation shall succeed. If the types are unknown automatic type +// conversion to a number is attempted. +func (v *Value) arithOp(op string, a *Value) error { + err := inferTypeForArithOp(v) + if err != nil { + return err + } + + err = inferTypeForArithOp(a) + if err != nil { + return err + } + + if !v.isNumeric() || !a.isNumeric() { + return errInvalidDataType(errArithMismatchedTypes) + } + + if !isValidArithOperator(op) { + return errInvalidDataType(errArithMismatchedTypes) + } + + intV, ok1i := v.ToInt() + intA, ok2i := a.ToInt() + switch { + case ok1i && ok2i: + res, err := intArithOp(op, intV, intA) + v.setInt(res) + return err + + default: + // Convert arguments to float + flV, _ := v.ToFloat() + flA, _ := a.ToFloat() + res, err := floatArithOp(op, flV, flA) + v.setFloat(res) + return err + } +} + +func inferTypeForArithOp(a *Value) error { + if _, ok := a.ToBytes(); !ok { return nil } - panic(fmt.Sprintf("requested bool value but found %T type", value.value)) -} - -// BoolValue - returns underlying bool value. It panics if value is not Bool type. -func (value *Value) BoolValue() bool { - if value.valueType == Bool { - return value.value.(bool) + if i, ok := a.bytesToInt(); ok { + a.setInt(i) + return nil } - panic(fmt.Sprintf("requested bool value but found %T type", value.value)) -} - -// IntValue - returns underlying int value. It panics if value is not Int type. -func (value *Value) IntValue() int64 { - if value.valueType == Int { - return value.value.(int64) + if f, ok := a.bytesToFloat(); ok { + a.setFloat(f) + return nil } - panic(fmt.Sprintf("requested int value but found %T type", value.value)) + err := fmt.Errorf("Could not convert %s to a number", string(a.value.([]byte))) + return errInvalidDataType(err) } -// FloatValue - returns underlying int/float value as float64. It panics if value is not Int/Float type. -func (value *Value) FloatValue() float64 { - switch value.valueType { - case Int: - return float64(value.value.(int64)) - case Float: - return value.value.(float64) +// All the bytesTo* functions defined below assume the value is a byte-slice. + +// Converts untyped value into int. The bool return implies success - +// it returns false only if there is a conversion failure. +func (v *Value) bytesToInt() (int64, bool) { + bytes, _ := v.ToBytes() + i, err := strconv.ParseInt(string(bytes), 10, 64) + return i, err == nil +} + +// Converts untyped value into float. The bool return implies success +// - it returns false only if there is a conversion failure. +func (v *Value) bytesToFloat() (float64, bool) { + bytes, _ := v.ToBytes() + i, err := strconv.ParseFloat(string(bytes), 64) + return i, err == nil +} + +// Converts untyped value into bool. The second bool return implies +// success - it returns false in case of a conversion failure. +func (v *Value) bytesToBool() (val bool, ok bool) { + bytes, _ := v.ToBytes() + ok = true + switch strings.ToLower(string(bytes)) { + case "t", "true": + val = true + case "f", "false": + val = false + default: + ok = false + } + return val, ok +} + +// bytesToString - never fails +func (v *Value) bytesToString() string { + bytes, _ := v.ToBytes() + return string(bytes) +} + +// Calculates minimum or maximum of v and a and assigns the result to +// v - it works only on numeric arguments, where `v` is already +// assumed to be numeric. Attempts conversion to numeric type for `a` +// (first int, then float) only if the underlying values do not have a +// type. +func (v *Value) minmax(a *Value, isMax, isFirstRow bool) error { + err := inferTypeForArithOp(a) + if err != nil { + return err } - panic(fmt.Sprintf("requested float value but found %T type", value.value)) -} - -// StringValue - returns underlying string value. It panics if value is not String type. -func (value *Value) StringValue() string { - if value.valueType == String { - return value.value.(string) + if !a.isNumeric() { + return errArithMismatchedTypes } - panic(fmt.Sprintf("requested string value but found %T type", value.value)) -} - -// TimeValue - returns underlying time value. It panics if value is not Timestamp type. -func (value *Value) TimeValue() time.Time { - if value.valueType == Timestamp { - return value.value.(time.Time) - } - - panic(fmt.Sprintf("requested time value but found %T type", value.value)) -} - -// ArrayValue - returns underlying value array. It panics if value is not Array type. -func (value *Value) ArrayValue() []*Value { - if value.valueType == Array { - return value.value.([]*Value) - } - - panic(fmt.Sprintf("requested array value but found %T type", value.value)) -} - -func (value *Value) recordValue() Record { - if value.valueType == record { - return value.value.(Record) - } - - panic(fmt.Sprintf("requested record value but found %T type", value.value)) -} - -// Type - returns value type. -func (value *Value) Type() Type { - return value.valueType -} - -// Value - returns underneath value interface. -func (value *Value) Value() interface{} { - return value.value -} - -// NewNull - creates new null value. -func NewNull() *Value { - return &Value{nil, Null} -} - -// NewBool - creates new Bool value of b. -func NewBool(b bool) *Value { - return &Value{b, Bool} -} - -// NewInt - creates new Int value of i. -func NewInt(i int64) *Value { - return &Value{i, Int} -} - -// NewFloat - creates new Float value of f. -func NewFloat(f float64) *Value { - return &Value{f, Float} -} - -// NewString - creates new Sring value of s. -func NewString(s string) *Value { - return &Value{s, String} -} - -// NewTime - creates new Time value of t. -func NewTime(t time.Time) *Value { - return &Value{t, Timestamp} -} - -// NewArray - creates new Array value of values. -func NewArray(values []*Value) *Value { - return &Value{values, Array} -} - -func newRecordValue(r Record) *Value { - return &Value{r, record} -} - -// NewValue - creates new Value from SQLVal v. -func NewValue(v *sqlparser.SQLVal) (*Value, error) { - switch v.Type { - case sqlparser.StrVal: - return NewString(string(v.Val)), nil - case sqlparser.IntVal: - i64, err := strconv.ParseInt(string(v.Val), 10, 64) - if err != nil { - return nil, err + // In case of first row, set v to a. + if isFirstRow { + intA, okI := a.ToInt() + if okI { + v.setInt(intA) + return nil } - return NewInt(i64), nil - case sqlparser.FloatVal: - f64, err := strconv.ParseFloat(string(v.Val), 64) - if err != nil { - return nil, err - } - return NewFloat(f64), nil - case sqlparser.HexNum: // represented as 0xDD - i64, err := strconv.ParseInt(string(v.Val), 16, 64) - if err != nil { - return nil, err - } - return NewInt(i64), nil - case sqlparser.HexVal: // represented as X'0DD' - i64, err := strconv.ParseInt(string(v.Val), 16, 64) - if err != nil { - return nil, err - } - return NewInt(i64), nil - case sqlparser.BitVal: // represented as B'00' - i64, err := strconv.ParseInt(string(v.Val), 2, 64) - if err != nil { - return nil, err - } - return NewInt(i64), nil - case sqlparser.ValArg: - // FIXME: the format is unknown and not sure how to handle it. + floatA, _ := a.ToFloat() + v.setFloat(floatA) + return nil } - return nil, fmt.Errorf("unknown SQL value %v; %v ", v, v.Type) + intV, ok1i := v.ToInt() + intA, ok2i := a.ToInt() + if ok1i && ok2i { + result := intV + if !isMax { + if intA < result { + result = intA + } + } else { + if intA > result { + result = intA + } + } + v.setInt(result) + return nil + } + + floatV, _ := v.ToFloat() + floatA, _ := a.ToFloat() + var result float64 + if !isMax { + result = math.Min(floatV, floatA) + } else { + result = math.Max(floatV, floatA) + } + v.setFloat(result) + return nil +} + +// inferTypeAsString is used to convert untyped values to string - it +// is called when the caller requires a string context to proceed. +func inferTypeAsString(v *Value) { + b, ok := v.ToBytes() + if !ok { + return + } + + v.setString(string(b)) +} + +func isValidComparisonOperator(op string) bool { + switch op { + case opLt: + case opLte: + case opGt: + case opGte: + case opEq: + case opIneq: + default: + return false + } + return true +} + +func intCompare(op string, left, right int64) bool { + switch op { + case opLt: + return left < right + case opLte: + return left <= right + case opGt: + return left > right + case opGte: + return left >= right + case opEq: + return left == right + case opIneq: + return left != right + } + // This case does not happen + return false +} + +func floatCompare(op string, left, right float64) bool { + switch op { + case opLt: + return left < right + case opLte: + return left <= right + case opGt: + return left > right + case opGte: + return left >= right + case opEq: + return left == right + case opIneq: + return left != right + } + // This case does not happen + return false +} + +func stringCompare(op string, left, right string) bool { + switch op { + case opLt: + return left < right + case opLte: + return left <= right + case opGt: + return left > right + case opGte: + return left >= right + case opEq: + return left == right + case opIneq: + return left != right + } + // This case does not happen + return false +} + +func boolCompare(op string, left, right bool) (bool, error) { + switch op { + case opEq: + return left == right, nil + case opIneq: + return left != right, nil + default: + return false, errCmpInvalidBoolOperator + } +} + +func isValidArithOperator(op string) bool { + switch op { + case opPlus: + case opMinus: + case opDivide: + case opMultiply: + case opModulo: + default: + return false + } + return true +} + +// Overflow errors are ignored. +func intArithOp(op string, left, right int64) (int64, error) { + switch op { + case opPlus: + return left + right, nil + case opMinus: + return left - right, nil + case opDivide: + if right == 0 { + return 0, errArithDivideByZero + } + return left / right, nil + case opMultiply: + return left * right, nil + case opModulo: + if right == 0 { + return 0, errArithDivideByZero + } + return left % right, nil + } + // This does not happen + return 0, nil +} + +// Overflow errors are ignored. +func floatArithOp(op string, left, right float64) (float64, error) { + switch op { + case opPlus: + return left + right, nil + case opMinus: + return left - right, nil + case opDivide: + if right == 0 { + return 0, errArithDivideByZero + } + return left / right, nil + case opMultiply: + return left * right, nil + case opModulo: + if right == 0 { + return 0, errArithDivideByZero + } + return math.Mod(left, right), nil + } + // This does not happen + return 0, nil } diff --git a/vendor/github.com/alecthomas/participle/COPYING b/vendor/github.com/alecthomas/participle/COPYING new file mode 100644 index 000000000..92dc39f70 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/COPYING @@ -0,0 +1,19 @@ +Copyright (C) 2017 Alec Thomas + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/alecthomas/participle/README.md b/vendor/github.com/alecthomas/participle/README.md new file mode 100644 index 000000000..3b61abc24 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/README.md @@ -0,0 +1,345 @@ +# A dead simple parser package for Go + +[![Godoc](https://godoc.org/github.com/alecthomas/participle?status.svg)](http://godoc.org/github.com/alecthomas/participle) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/participle.svg)](https://circleci.com/gh/alecthomas/participle) + [![Go Report Card](https://goreportcard.com/badge/github.com/alecthomas/participle)](https://goreportcard.com/report/github.com/alecthomas/participle) [![Gitter chat](https://badges.gitter.im/alecthomas.png)](https://gitter.im/alecthomas/Lobby) + + + +1. [Introduction](#introduction) +2. [Limitations](#limitations) +3. [Tutorial](#tutorial) +4. [Overview](#overview) +5. [Annotation syntax](#annotation-syntax) +6. [Capturing](#capturing) +7. [Streaming](#streaming) +8. [Lexing](#lexing) +9. [Options](#options) +10. [Examples](#examples) +11. [Performance](#performance) + + + + +## Introduction + +The goal of this package is to provide a simple, idiomatic and elegant way of +defining parsers in Go. + +Participle's method of defining grammars should be familiar to any Go +programmer who has used the `encoding/json` package: struct field tags define +what and how input is mapped to those same fields. This is not unusual for Go +encoders, but is unusual for a parser. + + +## Limitations + +Participle parsers are recursive descent. Among other things, this means that they do not support left recursion. + +There is an experimental lookahead option for using precomputed lookahead +tables for disambiguation. You can enable this with the parser option +`participle.UseLookahead()`. + +Left recursion must be eliminated by restructuring your grammar. + + +## Tutorial + +A [tutorial](TUTORIAL.md) is available, walking through the creation of an .ini parser. + + +## Overview + +A grammar is an annotated Go structure used to both define the parser grammar, +and be the AST output by the parser. As an example, following is the final INI +parser from the tutorial. + + ```go + type INI struct { + Properties []*Property `{ @@ }` + Sections []*Section `{ @@ }` + } + + type Section struct { + Identifier string `"[" @Ident "]"` + Properties []*Property `{ @@ }` + } + + type Property struct { + Key string `@Ident "="` + Value *Value `@@` + } + + type Value struct { + String *string ` @String` + Number *float64 `| @Float` + } + ``` + +> **Note:** Participle also supports named struct tags (eg. Hello string `parser:"@Ident"`). + +A parser is constructed from a grammar and a lexer: + +```go +parser, err := participle.Build(&INI{}) +``` + +Once constructed, the parser is applied to input to produce an AST: + +```go +ast := &INI{} +err := parser.ParseString("size = 10", ast) +// ast == &INI{ +// Properties: []*Property{ +// {Key: "size", Value: &Value{Number: &10}}, +// }, +// } +``` + + +## Annotation syntax + +- `@` Capture expression into the field. +- `@@` Recursively capture using the fields own type. +- `` Match named lexer token. +- `( ... )` Group. +- `"..."` Match the literal (note that the lexer must emit tokens matching this literal exactly). +- `"...":` Match the literal, specifying the exact lexer token type to match. +- ` ...` Match expressions. +- ` | ` Match one of the alternatives. + +The following modifiers can be used after any expression: + +- `*` Expression can match zero or more times. +- `+` Expression must match one or more times. +- `?` Expression can match zero or once. +- `!` Require a non-empty match (this is useful with a sequence of optional matches eg. `("a"? "b"? "c"?)!`). + +Supported but deprecated: +- `{ ... }` Match 0 or more times (**DEPRECATED** - prefer `( ... )*`). +- `[ ... ]` Optional (**DEPRECATED** - prefer `( ... )?`). + +Notes: + +- Each struct is a single production, with each field applied in sequence. +- `@` is the mechanism for capturing matches into the field. +- if a struct field is not keyed with "parser", the entire struct tag + will be used as the grammar fragment. This allows the grammar syntax to remain + clear and simple to maintain. + + +## Capturing + +Prefixing any expression in the grammar with `@` will capture matching values +for that expression into the corresponding field. + +For example: + +```go +// The grammar definition. +type Grammar struct { + Hello string `@Ident` +} + +// The source text to parse. +source := "world" + +// After parsing, the resulting AST. +result == &Grammar{ + Hello: "world", +} +``` + +For slice and string fields, each instance of `@` will accumulate into the +field (including repeated patterns). Accumulation into other types is not +supported. + +A successful capture match into a boolean field will set the field to true. + +For integer and floating point types, a successful capture will be parsed +with `strconv.ParseInt()` and `strconv.ParseBool()` respectively. + +Custom control of how values are captured into fields can be achieved by a +field type implementing the `Capture` interface (`Capture(values []string) +error`). + + +## Streaming + +Participle supports streaming parsing. Simply pass a channel of your grammar into +`Parse*()`. The grammar will be repeatedly parsed and sent to the channel. Note that +the `Parse*()` call will not return until parsing completes, so it should generally be +started in a goroutine. + +```go +type token struct { + Str string ` @Ident` + Num int `| @Int` +} + +parser, err := participle.Build(&token{}) + +tokens := make(chan *token, 128) +err := parser.ParseString(`hello 10 11 12 world`, tokens) +for token := range tokens { + fmt.Printf("%#v\n", token) +} +``` + + +## Lexing + +Participle operates on tokens and thus relies on a lexer to convert character +streams to tokens. + +Three lexers are provided, varying in speed and flexibility. The fastest lexer +is based on the [text/scanner](https://golang.org/pkg/text/scanner/) package +but only allows tokens provided by that package. Next fastest is the regexp +lexer (`lexer.Regexp()`). The slowest is currently the EBNF based lexer, but it has a large potential for optimisation through code generation. + +To use your own Lexer you will need to implement two interfaces: +[Definition](https://godoc.org/github.com/alecthomas/participle/lexer#Definition) +and [Lexer](https://godoc.org/github.com/alecthomas/participle/lexer#Lexer). + + +## Options + +The Parser's behaviour can be configured via [Options](https://godoc.org/github.com/alecthomas/participle#Option). + + +## Examples + +There are several [examples](https://github.com/alecthomas/participle/tree/master/_examples) included: + +Example | Description +--------|--------------- +[BASIC](https://github.com/alecthomas/participle/tree/master/_examples/basic) | A lexer, parser and interpreter for a [rudimentary dialect](https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora058.html) of BASIC. +[EBNF](https://github.com/alecthomas/participle/tree/master/_examples/ebnf) | Parser for the form of EBNF used by Go. +[Expr](https://github.com/alecthomas/participle/tree/master/_examples/expr) | A basic mathematical expression parser and evaluator. +[GraphQL](https://github.com/alecthomas/participle/tree/master/_examples/graphql) | Lexer+parser for GraphQL schemas +[HCL](https://github.com/alecthomas/participle/tree/master/_examples/hcl) | A parser for the [HashiCorp Configuration Language](https://github.com/hashicorp/hcl). +[INI](https://github.com/alecthomas/participle/tree/master/_examples/ini) | An INI file parser. +[Protobuf](https://github.com/alecthomas/participle/tree/master/_examples/protobuf) | A full [Protobuf](https://developers.google.com/protocol-buffers/) version 2 and 3 parser. +[SQL](https://github.com/alecthomas/participle/tree/master/_examples/sql) | A *very* rudimentary SQL SELECT parser. +[Thrift](https://github.com/alecthomas/participle/tree/master/_examples/thrift) | A full [Thrift](https://thrift.apache.org/docs/idl) parser. +[TOML](https://github.com/alecthomas/participle/blob/master/_examples/toml/main.go) | A [TOML](https://github.com/toml-lang/toml) parser. + +Included below is a full GraphQL lexer and parser: + +```go +package main + +import ( + "os" + + "github.com/alecthomas/kong" + "github.com/alecthomas/repr" + + "github.com/alecthomas/participle" + "github.com/alecthomas/participle/lexer" + "github.com/alecthomas/participle/lexer/ebnf" +) + +type File struct { + Entries []*Entry `{ @@ }` +} + +type Entry struct { + Type *Type ` @@` + Schema *Schema `| @@` + Enum *Enum `| @@` + Scalar string `| "scalar" @Ident` +} + +type Enum struct { + Name string `"enum" @Ident` + Cases []string `"{" { @Ident } "}"` +} + +type Schema struct { + Fields []*Field `"schema" "{" { @@ } "}"` +} + +type Type struct { + Name string `"type" @Ident` + Implements string `[ "implements" @Ident ]` + Fields []*Field `"{" { @@ } "}"` +} + +type Field struct { + Name string `@Ident` + Arguments []*Argument `[ "(" [ @@ { "," @@ } ] ")" ]` + Type *TypeRef `":" @@` + Annotation string `[ "@" @Ident ]` +} + +type Argument struct { + Name string `@Ident` + Type *TypeRef `":" @@` + Default *Value `[ "=" @@ ]` +} + +type TypeRef struct { + Array *TypeRef `( "[" @@ "]"` + Type string ` | @Ident )` + NonNullable bool `[ @"!" ]` +} + +type Value struct { + Symbol string `@Ident` +} + +var ( + graphQLLexer = lexer.Must(ebnf.New(` + Comment = ("#" | "//") { "\u0000"…"\uffff"-"\n" } . + Ident = (alpha | "_") { "_" | alpha | digit } . + Number = ("." | digit) {"." | digit} . + Whitespace = " " | "\t" | "\n" | "\r" . + Punct = "!"…"/" | ":"…"@" | "["…`+"\"`\""+` | "{"…"~" . + + alpha = "a"…"z" | "A"…"Z" . + digit = "0"…"9" . +`)) + + parser = participle.MustBuild(&File{}, + participle.Lexer(graphQLLexer), + participle.Elide("Comment", "Whitespace"), + ) + + cli struct { + Files []string `arg:"" type:"existingfile" required:"" help:"GraphQL schema files to parse."` + } +) + +func main() { + ctx := kong.Parse(&cli) + for _, file := range cli.Files { + ast := &File{} + r, err := os.Open(file) + ctx.FatalIfErrorf(err) + err = parser.Parse(r, ast) + r.Close() + repr.Println(ast) + ctx.FatalIfErrorf(err) + } +} + +``` + + +## Performance + +One of the included examples is a complete Thrift parser +(shell-style comments are not supported). This gives +a convenient baseline for comparing to the PEG based +[pigeon](https://github.com/PuerkitoBio/pigeon), which is the parser used by +[go-thrift](https://github.com/samuel/go-thrift). Additionally, the pigeon +parser is utilising a generated parser, while the participle parser is built at +run time. + +You can run the benchmarks yourself, but here's the output on my machine: + + BenchmarkParticipleThrift-4 10000 221818 ns/op 48880 B/op 1240 allocs/op + BenchmarkGoThriftParser-4 2000 804709 ns/op 170301 B/op 3086 allocs/op + +On a real life codebase of 47K lines of Thrift, Participle takes 200ms and go- +thrift takes 630ms, which aligns quite closely with the benchmarks. diff --git a/vendor/github.com/alecthomas/participle/TUTORIAL.md b/vendor/github.com/alecthomas/participle/TUTORIAL.md new file mode 100644 index 000000000..b2059507f --- /dev/null +++ b/vendor/github.com/alecthomas/participle/TUTORIAL.md @@ -0,0 +1,255 @@ +# Participle parser tutorial + + + +1. [Introduction](#introduction) +1. [The complete grammar](#the-complete-grammar) +1. [Root of the .ini AST \(structure, fields\)](#root-of-the-ini-ast-structure-fields) +1. [.ini properties \(named tokens, capturing, literals\)](#ini-properties-named-tokens-capturing-literals) +1. [.ini property values \(alternates, recursive structs, sequences\)](#ini-property-values-alternates-recursive-structs-sequences) +1. [Complete, but limited, .ini grammar \(top-level properties only\)](#complete-but-limited-ini-grammar-top-level-properties-only) +1. [Extending our grammar to support sections](#extending-our-grammar-to-support-sections) +1. [\(Optional\) Source positional information](#optional-source-positional-information) +1. [Parsing using our grammar](#parsing-using-our-grammar) + + + +## Introduction + +Writing a parser in Participle typically involves starting from the "root" of +the AST, annotating fields with the grammar, then recursively expanding until +it is complete. The AST is expressed via Go data types and the grammar is +expressed through struct field tags, as a form of EBNF. + +The parser we're going to create for this tutorial parses .ini files +like this: + +```ini +age = 21 +name = "Bob Smith" + +[address] +city = "Beverly Hills" +postal_code = 90210 +``` + +## The complete grammar + +I think it's useful to see the complete grammar first, to see what we're +working towards. Read on below for details. + + ```go + type INI struct { + Properties []*Property `@@*` + Sections []*Section `@@*` + } + + type Section struct { + Identifier string `"[" @Ident "]"` + Properties []*Property `@@*` + } + + type Property struct { + Key string `@Ident "="` + Value *Value `@@` + } + + type Value struct { + String *string ` @String` + Number *float64 `| @Float` + } + ``` + +## Root of the .ini AST (structure, fields) + +The first step is to create a root struct for our grammar. In the case of our +.ini parser, this struct will contain a sequence of properties: + +```go +type INI struct { + Properties []*Property +} + +type Property struct { +} +``` + +## .ini properties (named tokens, capturing, literals) + +Each property in an .ini file has an identifier key: + +```go +type Property struct { + Key string +} +``` + +The default lexer tokenises Go source code, and includes an `Ident` token type +that matches identifiers. To match this token we simply use the token type +name: + +```go +type Property struct { + Key string `Ident` +} +``` + +This will *match* identifiers, but not *capture* them into the `Key` field. To +capture input tokens into AST fields, prefix any grammar node with `@`: + +```go +type Property struct { + Key string `@Ident` +} +``` + +In .ini files, each key is separated from its value with a literal `=`. To +match a literal, enclose the literal in double quotes: + +```go +type Property struct { + Key string `@Ident "="` +} +``` + +> Note: literals in the grammar must match tokens from the lexer *exactly*. In +> this example if the lexer does not output `=` as a distinct token the +> grammar will not match. + +## .ini property values (alternates, recursive structs, sequences) + +For the purposes of our example we are only going to support quoted string +and numeric property values. As each value can be *either* a string or a float +we'll need something akin to a sum type. Go's type system cannot express this +directly, so we'll use the common approach of making each element a pointer. +The selected "case" will *not* be nil. + +```go +type Value struct { + String *string + Number *float64 +} +``` + +> Note: Participle will hydrate pointers as necessary. + +To express matching a set of alternatives we use the `|` operator: + +```go +type Value struct { + String *string ` @String` + Number *float64 `| @Float` +} +``` + +> Note: the grammar can cross fields. + +Next, we'll match values and capture them into the `Property`. To recursively +capture structs use `@@` (capture self): + +```go +type Property struct { + Key string `@Ident "="` + Value *Value `@@` +} +``` + +Now that we can parse a `Property` we need to go back to the root of the +grammar. We want to parse 0 or more properties. To do this, we use `*`. +Participle will accumulate each match into the slice until matching fails, +then move to the next node in the grammar. + +```go +type INI struct { + Properties []*Property `@@*` +} +``` + +> Note: tokens can also be accumulated into strings, appending each match. + +## Complete, but limited, .ini grammar (top-level properties only) + +We now have a functional, but limited, .ini parser! + +```go +type INI struct { + Properties []*Property `@@*` +} + +type Property struct { + Key string `@Ident "="` + Value *Value `@@` +} + +type Value struct { + String *string ` @String` + Number *float64 `| @Float` +} +``` + +## Extending our grammar to support sections + +Adding support for sections is simply a matter of utilising the constructs +we've just learnt. A section consists of a header identifier, and a sequence +of properties: + +```go +type Section struct { + Identifier string `"[" @Ident "]"` + Properties []*Property `@@*` +} +``` + +Simple! + +Now we just add a sequence of `Section`s to our root node: + +```go +type INI struct { + Properties []*Property `@@*` + Sections []*Section `@@*` +} +``` + +And we're done! + +## (Optional) Source positional information + +If a grammar node includes a field with the name `Pos` and type `lexer.Position`, it will be automatically populated by positional information. eg. + +```go +type Value struct { + Pos lexer.Position + String *string ` @String` + Number *float64 `| @Float` +} +``` + +This is useful for error reporting. + +## Parsing using our grammar + +To parse with this grammar we first construct the parser (we'll use the +default lexer for now): + +```go +parser, err := participle.Build(&INI{}) +``` + +Then create a root node and parse into it with `parser.Parse{,String,Bytes}()`: + +```go +ini := &INI{} +err = parser.ParseString(` +age = 21 +name = "Bob Smith" + +[address] +city = "Beverly Hills" +postal_code = 90210 +`, ini) +``` + +You can find the full example [here](_examples/ini/main.go), alongside +other examples including an SQL `SELECT` parser and a full +[Thrift](https://thrift.apache.org/) parser. diff --git a/vendor/github.com/alecthomas/participle/api.go b/vendor/github.com/alecthomas/participle/api.go new file mode 100644 index 000000000..dbcb8c778 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/api.go @@ -0,0 +1,19 @@ +package participle + +import ( + "github.com/alecthomas/participle/lexer" +) + +// Capture can be implemented by fields in order to transform captured tokens into field values. +type Capture interface { + Capture(values []string) error +} + +// The Parseable interface can be implemented by any element in the grammar to provide custom parsing. +type Parseable interface { + // Parse into the receiver. + // + // Should return NextMatch if no tokens matched and parsing should continue. + // Nil should be returned if parsing was successful. + Parse(lex lexer.PeekingLexer) error +} diff --git a/vendor/github.com/alecthomas/participle/context.go b/vendor/github.com/alecthomas/participle/context.go new file mode 100644 index 000000000..9b3e11a28 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/context.go @@ -0,0 +1,123 @@ +package participle + +import ( + "reflect" + + "github.com/alecthomas/participle/lexer" +) + +type contextFieldSet struct { + pos lexer.Position + strct reflect.Value + field structLexerField + fieldValue []reflect.Value +} + +// Context for a single parse. +type parseContext struct { + *rewinder + lookahead int + caseInsensitive map[rune]bool + apply []*contextFieldSet +} + +func newParseContext(lex lexer.Lexer, lookahead int, caseInsensitive map[rune]bool) (*parseContext, error) { + rew, err := newRewinder(lex) + if err != nil { + return nil, err + } + return &parseContext{ + rewinder: rew, + caseInsensitive: caseInsensitive, + lookahead: lookahead, + }, nil +} + +// Defer adds a function to be applied once a branch has been picked. +func (p *parseContext) Defer(pos lexer.Position, strct reflect.Value, field structLexerField, fieldValue []reflect.Value) { + p.apply = append(p.apply, &contextFieldSet{pos, strct, field, fieldValue}) +} + +// Apply deferred functions. +func (p *parseContext) Apply() error { + for _, apply := range p.apply { + if err := setField(apply.pos, apply.strct, apply.field, apply.fieldValue); err != nil { + return err + } + } + p.apply = nil + return nil +} + +// Branch accepts the branch as the correct branch. +func (p *parseContext) Accept(branch *parseContext) { + p.apply = append(p.apply, branch.apply...) + p.rewinder = branch.rewinder +} + +// Branch starts a new lookahead branch. +func (p *parseContext) Branch() *parseContext { + branch := &parseContext{} + *branch = *p + branch.apply = nil + branch.rewinder = p.rewinder.Lookahead() + return branch +} + +// Stop returns true if parsing should terminate after the given "branch" failed to match. +func (p *parseContext) Stop(branch *parseContext) bool { + if branch.cursor > p.cursor+p.lookahead { + p.Accept(branch) + return true + } + return false +} + +type rewinder struct { + cursor, limit int + tokens []lexer.Token +} + +func newRewinder(lex lexer.Lexer) (*rewinder, error) { + r := &rewinder{} + for { + t, err := lex.Next() + if err != nil { + return nil, err + } + if t.EOF() { + break + } + r.tokens = append(r.tokens, t) + } + return r, nil +} + +func (r *rewinder) Next() (lexer.Token, error) { + if r.cursor >= len(r.tokens) { + return lexer.EOFToken(lexer.Position{}), nil + } + r.cursor++ + return r.tokens[r.cursor-1], nil +} + +func (r *rewinder) Peek(n int) (lexer.Token, error) { + i := r.cursor + n + if i >= len(r.tokens) { + return lexer.EOFToken(lexer.Position{}), nil + } + return r.tokens[i], nil +} + +// Lookahead returns a new rewinder usable for lookahead. +func (r *rewinder) Lookahead() *rewinder { + clone := &rewinder{} + *clone = *r + clone.limit = clone.cursor + return clone +} + +// Keep this lookahead rewinder. +func (r *rewinder) Keep() { + r.limit = 0 +} diff --git a/vendor/github.com/alecthomas/participle/doc.go b/vendor/github.com/alecthomas/participle/doc.go new file mode 100644 index 000000000..4e0b73cbb --- /dev/null +++ b/vendor/github.com/alecthomas/participle/doc.go @@ -0,0 +1,73 @@ +// Package participle constructs parsers from definitions in struct tags and parses directly into +// those structs. The approach is philosophically similar to how other marshallers work in Go, +// "unmarshalling" an instance of a grammar into a struct. +// +// The supported annotation syntax is: +// +// - `@` Capture expression into the field. +// - `@@` Recursively capture using the fields own type. +// - `` Match named lexer token. +// - `( ... )` Group. +// - `"..."` Match the literal (note that the lexer must emit tokens matching this literal exactly). +// - `"...":` Match the literal, specifying the exact lexer token type to match. +// - ` ...` Match expressions. +// - ` | ` Match one of the alternatives. +// +// The following modifiers can be used after any expression: +// +// - `*` Expression can match zero or more times. +// - `+` Expression must match one or more times. +// - `?` Expression can match zero or once. +// - `!` Require a non-empty match (this is useful with a sequence of optional matches eg. `("a"? "b"? "c"?)!`). +// +// Supported but deprecated: +// +// - `{ ... }` Match 0 or more times (**DEPRECATED** - prefer `( ... )*`). +// - `[ ... ]` Optional (**DEPRECATED** - prefer `( ... )?`). +// +// Here's an example of an EBNF grammar. +// +// type Group struct { +// Expression *Expression `"(" @@ ")"` +// } +// +// type Option struct { +// Expression *Expression `"[" @@ "]"` +// } +// +// type Repetition struct { +// Expression *Expression `"{" @@ "}"` +// } +// +// type Literal struct { +// Start string `@String` // lexer.Lexer token "String" +// End string `("…" @String)?` +// } +// +// type Term struct { +// Name string ` @Ident` +// Literal *Literal `| @@` +// Group *Group `| @@` +// Option *Option `| @@` +// Repetition *Repetition `| @@` +// } +// +// type Sequence struct { +// Terms []*Term `@@+` +// } +// +// type Expression struct { +// Alternatives []*Sequence `@@ ("|" @@)*` +// } +// +// type Expressions []*Expression +// +// type Production struct { +// Name string `@Ident "="` +// Expressions Expressions `@@+ "."` +// } +// +// type EBNF struct { +// Productions []*Production `@@*` +// } +package participle diff --git a/vendor/github.com/alecthomas/participle/go.mod b/vendor/github.com/alecthomas/participle/go.mod new file mode 100644 index 000000000..b02f97e68 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/go.mod @@ -0,0 +1,7 @@ +module github.com/alecthomas/participle + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.2.2 +) diff --git a/vendor/github.com/alecthomas/participle/go.sum b/vendor/github.com/alecthomas/participle/go.sum new file mode 100644 index 000000000..e03ee77d9 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/go.sum @@ -0,0 +1,6 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/vendor/github.com/alecthomas/participle/grammar.go b/vendor/github.com/alecthomas/participle/grammar.go new file mode 100644 index 000000000..2e85bbc22 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/grammar.go @@ -0,0 +1,324 @@ +package participle + +import ( + "fmt" + "reflect" + "text/scanner" + + "github.com/alecthomas/participle/lexer" +) + +type generatorContext struct { + lexer.Definition + typeNodes map[reflect.Type]node + symbolsToIDs map[rune]string +} + +func newGeneratorContext(lex lexer.Definition) *generatorContext { + return &generatorContext{ + Definition: lex, + typeNodes: map[reflect.Type]node{}, + symbolsToIDs: lexer.SymbolsByRune(lex), + } +} + +// Takes a type and builds a tree of nodes out of it. +func (g *generatorContext) parseType(t reflect.Type) (_ node, returnedError error) { + rt := t + t = indirectType(t) + if n, ok := g.typeNodes[t]; ok { + return n, nil + } + if rt.Implements(parseableType) { + return &parseable{rt.Elem()}, nil + } + if reflect.PtrTo(rt).Implements(parseableType) { + return &parseable{rt}, nil + } + switch t.Kind() { + case reflect.Slice, reflect.Ptr: + t = indirectType(t.Elem()) + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("expected a struct but got %T", t) + } + fallthrough + + case reflect.Struct: + slexer, err := lexStruct(t) + if err != nil { + return nil, err + } + out := &strct{typ: t} + g.typeNodes[t] = out // Ensure we avoid infinite recursion. + if slexer.NumField() == 0 { + return nil, fmt.Errorf("can not parse into empty struct %s", t) + } + defer decorate(&returnedError, func() string { return slexer.Field().Name }) + e, err := g.parseDisjunction(slexer) + if err != nil { + return nil, err + } + if e == nil { + return nil, fmt.Errorf("no grammar found in %s", t) + } + if token, _ := slexer.Peek(); !token.EOF() { + return nil, fmt.Errorf("unexpected input %q", token.Value) + } + out.expr = e + return out, nil + } + return nil, fmt.Errorf("%s should be a struct or should implement the Parseable interface", t) +} + +func (g *generatorContext) parseDisjunction(slexer *structLexer) (node, error) { + out := &disjunction{} + for { + n, err := g.parseSequence(slexer) + if err != nil { + return nil, err + } + out.nodes = append(out.nodes, n) + if token, _ := slexer.Peek(); token.Type != '|' { + break + } + _, err = slexer.Next() // | + if err != nil { + return nil, err + } + } + if len(out.nodes) == 1 { + return out.nodes[0], nil + } + return out, nil +} + +func (g *generatorContext) parseSequence(slexer *structLexer) (node, error) { + head := &sequence{} + cursor := head +loop: + for { + if token, err := slexer.Peek(); err != nil { + return nil, err + } else if token.Type == lexer.EOF { + break loop + } + term, err := g.parseTerm(slexer) + if err != nil { + return nil, err + } + if term == nil { + break loop + } + if cursor.node == nil { + cursor.head = true + cursor.node = term + } else { + cursor.next = &sequence{node: term} + cursor = cursor.next + } + } + if head.node == nil { + return nil, nil + } + if head.next == nil { + return head.node, nil + } + return head, nil +} + +func (g *generatorContext) parseTermNoModifiers(slexer *structLexer) (node, error) { + t, err := slexer.Peek() + if err != nil { + return nil, err + } + var out node + switch t.Type { + case '@': + out, err = g.parseCapture(slexer) + case scanner.String, scanner.RawString, scanner.Char: + out, err = g.parseLiteral(slexer) + case '[': + return g.parseOptional(slexer) + case '{': + return g.parseRepetition(slexer) + case '(': + out, err = g.parseGroup(slexer) + case scanner.Ident: + out, err = g.parseReference(slexer) + case lexer.EOF: + _, _ = slexer.Next() + return nil, nil + default: + return nil, nil + } + return out, err +} + +func (g *generatorContext) parseTerm(slexer *structLexer) (node, error) { + out, err := g.parseTermNoModifiers(slexer) + if err != nil { + return nil, err + } + return g.parseModifier(slexer, out) +} + +// Parse modifiers: ?, *, + and/or ! +func (g *generatorContext) parseModifier(slexer *structLexer, expr node) (node, error) { + out := &group{expr: expr} + t, err := slexer.Peek() + if err != nil { + return nil, err + } + switch t.Type { + case '!': + out.mode = groupMatchNonEmpty + case '+': + out.mode = groupMatchOneOrMore + case '*': + out.mode = groupMatchZeroOrMore + case '?': + out.mode = groupMatchZeroOrOne + default: + return expr, nil + } + _, _ = slexer.Next() + return out, nil +} + +// @ captures into the current field. +func (g *generatorContext) parseCapture(slexer *structLexer) (node, error) { + _, _ = slexer.Next() + token, err := slexer.Peek() + if err != nil { + return nil, err + } + field := slexer.Field() + if token.Type == '@' { + _, _ = slexer.Next() + n, err := g.parseType(field.Type) + if err != nil { + return nil, err + } + return &capture{field, n}, nil + } + if indirectType(field.Type).Kind() == reflect.Struct && !field.Type.Implements(captureType) { + return nil, fmt.Errorf("structs can only be parsed with @@ or by implementing the Capture interface") + } + n, err := g.parseTermNoModifiers(slexer) + if err != nil { + return nil, err + } + return &capture{field, n}, nil +} + +// A reference in the form refers to a named token from the lexer. +func (g *generatorContext) parseReference(slexer *structLexer) (node, error) { // nolint: interfacer + token, err := slexer.Next() + if err != nil { + return nil, err + } + if token.Type != scanner.Ident { + return nil, fmt.Errorf("expected identifier but got %q", token) + } + typ, ok := g.Symbols()[token.Value] + if !ok { + return nil, fmt.Errorf("unknown token type %q", token) + } + return &reference{typ: typ, identifier: token.Value}, nil +} + +// [ ] optionally matches . +func (g *generatorContext) parseOptional(slexer *structLexer) (node, error) { + _, _ = slexer.Next() // [ + disj, err := g.parseDisjunction(slexer) + if err != nil { + return nil, err + } + n := &group{expr: disj, mode: groupMatchZeroOrOne} + next, err := slexer.Next() + if err != nil { + return nil, err + } + if next.Type != ']' { + return nil, fmt.Errorf("expected ] but got %q", next) + } + return n, nil +} + +// { } matches 0 or more repititions of +func (g *generatorContext) parseRepetition(slexer *structLexer) (node, error) { + _, _ = slexer.Next() // { + disj, err := g.parseDisjunction(slexer) + if err != nil { + return nil, err + } + n := &group{expr: disj, mode: groupMatchZeroOrMore} + next, err := slexer.Next() + if err != nil { + return nil, err + } + if next.Type != '}' { + return nil, fmt.Errorf("expected } but got %q", next) + } + return n, nil +} + +// ( ) groups a sub-expression +func (g *generatorContext) parseGroup(slexer *structLexer) (node, error) { + _, _ = slexer.Next() // ( + disj, err := g.parseDisjunction(slexer) + if err != nil { + return nil, err + } + next, err := slexer.Next() // ) + if err != nil { + return nil, err + } + if next.Type != ')' { + return nil, fmt.Errorf("expected ) but got %q", next) + } + return &group{expr: disj}, nil +} + +// A literal string. +// +// Note that for this to match, the tokeniser must be able to produce this string. For example, +// if the tokeniser only produces individual characters but the literal is "hello", or vice versa. +func (g *generatorContext) parseLiteral(lex *structLexer) (node, error) { // nolint: interfacer + token, err := lex.Next() + if err != nil { + return nil, err + } + if token.Type != scanner.String && token.Type != scanner.RawString && token.Type != scanner.Char { + return nil, fmt.Errorf("expected quoted string but got %q", token) + } + s := token.Value + t := rune(-1) + token, err = lex.Peek() + if err != nil { + return nil, err + } + if token.Value == ":" && (token.Type == scanner.Char || token.Type == ':') { + _, _ = lex.Next() + token, err = lex.Next() + if err != nil { + return nil, err + } + if token.Type != scanner.Ident { + return nil, fmt.Errorf("expected identifier for literal type constraint but got %q", token) + } + var ok bool + t, ok = g.Symbols()[token.Value] + if !ok { + return nil, fmt.Errorf("unknown token type %q in literal type constraint", token) + } + } + return &literal{s: s, t: t, tt: g.symbolsToIDs[t]}, nil +} + +func indirectType(t reflect.Type) reflect.Type { + if t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice { + return indirectType(t.Elem()) + } + return t +} diff --git a/vendor/github.com/alecthomas/participle/lexer/doc.go b/vendor/github.com/alecthomas/participle/lexer/doc.go new file mode 100644 index 000000000..d0fc01085 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/doc.go @@ -0,0 +1,19 @@ +// Package lexer defines interfaces and implementations used by Participle to perform lexing. +// +// The primary interfaces are Definition and Lexer. There are three implementations of these +// interfaces: +// +// TextScannerLexer is based on text/scanner. This is the fastest, but least flexible, in that +// tokens are restricted to those supported by that package. It can scan about 5M tokens/second on a +// late 2013 15" MacBook Pro. +// +// The second lexer is constructed via the Regexp() function, mapping regexp capture groups +// to tokens. The complete input source is read into memory, so it is unsuitable for large inputs. +// +// The final lexer provided accepts a lexical grammar in EBNF. Each capitalised production is a +// lexical token supported by the resulting Lexer. This is very flexible, but a bit slower, scanning +// around 730K tokens/second on the same machine, though it is currently completely unoptimised. +// This could/should be converted to a table-based lexer. +// +// Lexer implementations must use Panic/Panicf to report errors. +package lexer diff --git a/vendor/github.com/alecthomas/participle/lexer/errors.go b/vendor/github.com/alecthomas/participle/lexer/errors.go new file mode 100644 index 000000000..8f8dc62e8 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/errors.go @@ -0,0 +1,26 @@ +package lexer + +import "fmt" + +// Error represents an error while parsing. +type Error struct { + Message string + Pos Position +} + +// Errorf creats a new Error at the given position. +func Errorf(pos Position, format string, args ...interface{}) *Error { + return &Error{ + Message: fmt.Sprintf(format, args...), + Pos: pos, + } +} + +// Error complies with the error interface and reports the position of an error. +func (e *Error) Error() string { + filename := e.Pos.Filename + if filename == "" { + filename = "" + } + return fmt.Sprintf("%s:%d:%d: %s", filename, e.Pos.Line, e.Pos.Column, e.Message) +} diff --git a/vendor/github.com/alecthomas/participle/lexer/lexer.go b/vendor/github.com/alecthomas/participle/lexer/lexer.go new file mode 100644 index 000000000..8b0ec3a13 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/lexer.go @@ -0,0 +1,150 @@ +package lexer + +import ( + "fmt" + "io" +) + +const ( + // EOF represents an end of file. + EOF rune = -(iota + 1) +) + +// EOFToken creates a new EOF token at the given position. +func EOFToken(pos Position) Token { + return Token{Type: EOF, Pos: pos} +} + +// Definition provides the parser with metadata for a lexer. +type Definition interface { + // Lex an io.Reader. + Lex(io.Reader) (Lexer, error) + // Symbols returns a map of symbolic names to the corresponding pseudo-runes for those symbols. + // This is the same approach as used by text/scanner. For example, "EOF" might have the rune + // value of -1, "Ident" might be -2, and so on. + Symbols() map[string]rune +} + +// A Lexer returns tokens from a source. +type Lexer interface { + // Next consumes and returns the next token. + Next() (Token, error) +} + +// A PeekingLexer returns tokens from a source and allows peeking. +type PeekingLexer interface { + Lexer + // Peek at the next token. + Peek(n int) (Token, error) +} + +// SymbolsByRune returns a map of lexer symbol names keyed by rune. +func SymbolsByRune(def Definition) map[rune]string { + out := map[rune]string{} + for s, r := range def.Symbols() { + out[r] = s + } + return out +} + +// NameOfReader attempts to retrieve the filename of a reader. +func NameOfReader(r interface{}) string { + if nr, ok := r.(interface{ Name() string }); ok { + return nr.Name() + } + return "" +} + +// Must takes the result of a Definition constructor call and returns the definition, but panics if +// it errors +// +// eg. +// +// lex = lexer.Must(lexer.Build(`Symbol = "symbol" .`)) +func Must(def Definition, err error) Definition { + if err != nil { + panic(err) + } + return def +} + +// ConsumeAll reads all tokens from a Lexer. +func ConsumeAll(lexer Lexer) ([]Token, error) { + tokens := []Token{} + for { + token, err := lexer.Next() + if err != nil { + return nil, err + } + tokens = append(tokens, token) + if token.Type == EOF { + return tokens, nil + } + } +} + +// Position of a token. +type Position struct { + Filename string + Offset int + Line int + Column int +} + +func (p Position) GoString() string { + return fmt.Sprintf("Position{Filename: %q, Offset: %d, Line: %d, Column: %d}", + p.Filename, p.Offset, p.Line, p.Column) +} + +func (p Position) String() string { + filename := p.Filename + if filename == "" { + filename = "" + } + return fmt.Sprintf("%s:%d:%d", filename, p.Line, p.Column) +} + +// A Token returned by a Lexer. +type Token struct { + // Type of token. This is the value keyed by symbol as returned by Definition.Symbols(). + Type rune + Value string + Pos Position +} + +// RuneToken represents a rune as a Token. +func RuneToken(r rune) Token { + return Token{Type: r, Value: string(r)} +} + +// EOF returns true if this Token is an EOF token. +func (t Token) EOF() bool { + return t.Type == EOF +} + +func (t Token) String() string { + if t.EOF() { + return "" + } + return t.Value +} + +func (t Token) GoString() string { + return fmt.Sprintf("Token{%d, %q}", t.Type, t.Value) +} + +// MakeSymbolTable builds a lookup table for checking token ID existence. +// +// For each symbolic name in "types", the returned map will contain the corresponding token ID as a key. +func MakeSymbolTable(def Definition, types ...string) (map[rune]bool, error) { + symbols := def.Symbols() + table := map[rune]bool{} + for _, symbol := range types { + rn, ok := symbols[symbol] + if !ok { + return nil, fmt.Errorf("lexer does not support symbol %q", symbol) + } + table[rn] = true + } + return table, nil +} diff --git a/vendor/github.com/alecthomas/participle/lexer/peek.go b/vendor/github.com/alecthomas/participle/lexer/peek.go new file mode 100644 index 000000000..11246e243 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/peek.go @@ -0,0 +1,37 @@ +package lexer + +// Upgrade a Lexer to a PeekingLexer with arbitrary lookahead. +func Upgrade(lexer Lexer) PeekingLexer { + if peeking, ok := lexer.(PeekingLexer); ok { + return peeking + } + return &lookaheadLexer{Lexer: lexer} +} + +type lookaheadLexer struct { + Lexer + peeked []Token +} + +func (l *lookaheadLexer) Peek(n int) (Token, error) { + for len(l.peeked) <= n { + t, err := l.Lexer.Next() + if err != nil { + return Token{}, err + } + if t.EOF() { + return t, nil + } + l.peeked = append(l.peeked, t) + } + return l.peeked[n], nil +} + +func (l *lookaheadLexer) Next() (Token, error) { + if len(l.peeked) > 0 { + t := l.peeked[0] + l.peeked = l.peeked[1:] + return t, nil + } + return l.Lexer.Next() +} diff --git a/vendor/github.com/alecthomas/participle/lexer/regexp.go b/vendor/github.com/alecthomas/participle/lexer/regexp.go new file mode 100644 index 000000000..ea56fe931 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/regexp.go @@ -0,0 +1,112 @@ +package lexer + +import ( + "bytes" + "io" + "io/ioutil" + "regexp" + "unicode/utf8" +) + +var eolBytes = []byte("\n") + +type regexpDefinition struct { + re *regexp.Regexp + symbols map[string]rune +} + +// Regexp creates a lexer definition from a regular expression. +// +// Each named sub-expression in the regular expression matches a token. Anonymous sub-expressions +// will be matched and discarded. +// +// eg. +// +// def, err := Regexp(`(?P[a-z]+)|(\s+)|(?P\d+)`) +func Regexp(pattern string) (Definition, error) { + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + symbols := map[string]rune{ + "EOF": EOF, + } + for i, sym := range re.SubexpNames()[1:] { + if sym != "" { + symbols[sym] = EOF - 1 - rune(i) + } + } + return ®expDefinition{re: re, symbols: symbols}, nil +} + +func (d *regexpDefinition) Lex(r io.Reader) (Lexer, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return ®expLexer{ + pos: Position{ + Filename: NameOfReader(r), + Line: 1, + Column: 1, + }, + b: b, + re: d.re, + names: d.re.SubexpNames(), + }, nil +} + +func (d *regexpDefinition) Symbols() map[string]rune { + return d.symbols +} + +type regexpLexer struct { + pos Position + b []byte + re *regexp.Regexp + names []string +} + +func (r *regexpLexer) Next() (Token, error) { +nextToken: + for len(r.b) != 0 { + matches := r.re.FindSubmatchIndex(r.b) + if matches == nil || matches[0] != 0 { + rn, _ := utf8.DecodeRune(r.b) + return Token{}, Errorf(r.pos, "invalid token %q", rn) + } + match := r.b[:matches[1]] + token := Token{ + Pos: r.pos, + Value: string(match), + } + + // Update lexer state. + r.pos.Offset += matches[1] + lines := bytes.Count(match, eolBytes) + r.pos.Line += lines + // Update column. + if lines == 0 { + r.pos.Column += utf8.RuneCount(match) + } else { + r.pos.Column = utf8.RuneCount(match[bytes.LastIndex(match, eolBytes):]) + } + // Move slice along. + r.b = r.b[matches[1]:] + + // Finally, assign token type. If it is not a named group, we continue to the next token. + for i := 2; i < len(matches); i += 2 { + if matches[i] != -1 { + if r.names[i/2] == "" { + continue nextToken + } + token.Type = EOF - rune(i/2) + break + } + } + + return token, nil + } + + return EOFToken(r.pos), nil +} diff --git a/vendor/github.com/alecthomas/participle/lexer/text_scanner.go b/vendor/github.com/alecthomas/participle/lexer/text_scanner.go new file mode 100644 index 000000000..bc26362d0 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/lexer/text_scanner.go @@ -0,0 +1,125 @@ +package lexer + +import ( + "bytes" + "fmt" + "io" + "strconv" + "strings" + "text/scanner" + "unicode/utf8" +) + +// TextScannerLexer is a lexer that uses the text/scanner module. +var ( + TextScannerLexer Definition = &defaultDefinition{} + + // DefaultDefinition defines properties for the default lexer. + DefaultDefinition = TextScannerLexer +) + +type defaultDefinition struct{} + +func (d *defaultDefinition) Lex(r io.Reader) (Lexer, error) { + return Lex(r), nil +} + +func (d *defaultDefinition) Symbols() map[string]rune { + return map[string]rune{ + "EOF": scanner.EOF, + "Char": scanner.Char, + "Ident": scanner.Ident, + "Int": scanner.Int, + "Float": scanner.Float, + "String": scanner.String, + "RawString": scanner.RawString, + "Comment": scanner.Comment, + } +} + +// textScannerLexer is a Lexer based on text/scanner.Scanner +type textScannerLexer struct { + scanner *scanner.Scanner + filename string + err error +} + +// Lex an io.Reader with text/scanner.Scanner. +// +// This provides very fast lexing of source code compatible with Go tokens. +// +// Note that this differs from text/scanner.Scanner in that string tokens will be unquoted. +func Lex(r io.Reader) Lexer { + lexer := lexWithScanner(r, &scanner.Scanner{}) + lexer.scanner.Error = func(s *scanner.Scanner, msg string) { + // This is to support single quoted strings. Hacky. + if msg != "illegal char literal" { + lexer.err = Errorf(Position(lexer.scanner.Pos()), msg) + } + } + return lexer +} + +// LexWithScanner creates a Lexer from a user-provided scanner.Scanner. +// +// Useful if you need to customise the Scanner. +func LexWithScanner(r io.Reader, scan *scanner.Scanner) Lexer { + return lexWithScanner(r, scan) +} + +func lexWithScanner(r io.Reader, scan *scanner.Scanner) *textScannerLexer { + lexer := &textScannerLexer{ + filename: NameOfReader(r), + scanner: scan, + } + lexer.scanner.Init(r) + return lexer +} + +// LexBytes returns a new default lexer over bytes. +func LexBytes(b []byte) Lexer { + return Lex(bytes.NewReader(b)) +} + +// LexString returns a new default lexer over a string. +func LexString(s string) Lexer { + return Lex(strings.NewReader(s)) +} + +func (t *textScannerLexer) Next() (Token, error) { + typ := t.scanner.Scan() + text := t.scanner.TokenText() + pos := Position(t.scanner.Position) + pos.Filename = t.filename + if t.err != nil { + return Token{}, t.err + } + return textScannerTransform(Token{ + Type: typ, + Value: text, + Pos: pos, + }) +} + +func textScannerTransform(token Token) (Token, error) { + // Unquote strings. + switch token.Type { + case scanner.Char: + // FIXME(alec): This is pretty hacky...we convert a single quoted char into a double + // quoted string in order to support single quoted strings. + token.Value = fmt.Sprintf("\"%s\"", token.Value[1:len(token.Value)-1]) + fallthrough + case scanner.String: + s, err := strconv.Unquote(token.Value) + if err != nil { + return Token{}, Errorf(token.Pos, "%s: %q", err.Error(), token.Value) + } + token.Value = s + if token.Type == scanner.Char && utf8.RuneCountInString(s) > 1 { + token.Type = scanner.String + } + case scanner.RawString: + token.Value = token.Value[1 : len(token.Value)-1] + } + return token, nil +} diff --git a/vendor/github.com/alecthomas/participle/map.go b/vendor/github.com/alecthomas/participle/map.go new file mode 100644 index 000000000..99e80c773 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/map.go @@ -0,0 +1,118 @@ +package participle + +import ( + "errors" + "io" + "strconv" + "strings" + + "github.com/alecthomas/participle/lexer" +) + +type mapperByToken struct { + symbols []string + mapper Mapper +} + +// DropToken can be returned by a Mapper to remove a token from the stream. +var DropToken = errors.New("drop token") // nolint: golint + +// Mapper function for mutating tokens before being applied to the AST. +// +// If the Mapper func returns an error of DropToken, the token will be removed from the stream. +type Mapper func(token lexer.Token) (lexer.Token, error) + +// Map is an Option that configures the Parser to apply a mapping function to each Token from the lexer. +// +// This can be useful to eg. upper-case all tokens of a certain type, or dequote strings. +// +// "symbols" specifies the token symbols that the Mapper will be applied to. If empty, all tokens will be mapped. +func Map(mapper Mapper, symbols ...string) Option { + return func(p *Parser) error { + p.mappers = append(p.mappers, mapperByToken{ + mapper: mapper, + symbols: symbols, + }) + return nil + } +} + +// Unquote applies strconv.Unquote() to tokens of the given types. +// +// Tokens of type "String" will be unquoted if no other types are provided. +func Unquote(types ...string) Option { + if len(types) == 0 { + types = []string{"String"} + } + return Map(func(t lexer.Token) (lexer.Token, error) { + value, err := unquote(t.Value) + if err != nil { + return t, lexer.Errorf(t.Pos, "invalid quoted string %q: %s", t.Value, err.Error()) + } + t.Value = value + return t, nil + }, types...) +} + +func unquote(s string) (string, error) { + quote := s[0] + s = s[1 : len(s)-1] + out := "" + for s != "" { + value, _, tail, err := strconv.UnquoteChar(s, quote) + if err != nil { + return "", err + } + s = tail + out += string(value) + } + return out, nil +} + +// Upper is an Option that upper-cases all tokens of the given type. Useful for case normalisation. +func Upper(types ...string) Option { + return Map(func(token lexer.Token) (lexer.Token, error) { + token.Value = strings.ToUpper(token.Value) + return token, nil + }, types...) +} + +// Elide drops tokens of the specified types. +func Elide(types ...string) Option { + return Map(func(token lexer.Token) (lexer.Token, error) { + return lexer.Token{}, DropToken + }, types...) +} + +// Apply a Mapping to all tokens coming out of a Lexer. +type mappingLexerDef struct { + lexer.Definition + mapper Mapper +} + +func (m *mappingLexerDef) Lex(r io.Reader) (lexer.Lexer, error) { + lexer, err := m.Definition.Lex(r) + if err != nil { + return nil, err + } + return &mappingLexer{lexer, m.mapper}, nil +} + +type mappingLexer struct { + lexer.Lexer + mapper Mapper +} + +func (m *mappingLexer) Next() (lexer.Token, error) { + for { + t, err := m.Lexer.Next() + if err != nil { + return t, err + } + t, err = m.mapper(t) + if err == DropToken { + continue + } + return t, err + } +} diff --git a/vendor/github.com/alecthomas/participle/nodes.go b/vendor/github.com/alecthomas/participle/nodes.go new file mode 100644 index 000000000..f77357c99 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/nodes.go @@ -0,0 +1,575 @@ +package participle + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" + + "github.com/alecthomas/participle/lexer" +) + +var ( + // MaxIterations limits the number of elements capturable by {}. + MaxIterations = 1000000 + + positionType = reflect.TypeOf(lexer.Position{}) + captureType = reflect.TypeOf((*Capture)(nil)).Elem() + parseableType = reflect.TypeOf((*Parseable)(nil)).Elem() + + // NextMatch should be returned by Parseable.Parse() method implementations to indicate + // that the node did not match and that other matches should be attempted, if appropriate. + NextMatch = errors.New("no match") // nolint: golint +) + +// A node in the grammar. +type node interface { + // Parse from scanner into value. + // + // Returned slice will be nil if the node does not match. + Parse(ctx *parseContext, parent reflect.Value) ([]reflect.Value, error) + + // Return a decent string representation of the Node. + String() string +} + +func decorate(err *error, name func() string) { + if *err == nil { + return + } + switch realError := (*err).(type) { + case *lexer.Error: + *err = &lexer.Error{Message: name() + ": " + realError.Message, Pos: realError.Pos} + default: + *err = fmt.Errorf("%s: %s", name(), realError) + } +} + +// A node that proxies to an implementation that implements the Parseable interface. +type parseable struct { + t reflect.Type +} + +func (p *parseable) String() string { return stringer(p) } + +func (p *parseable) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + rv := reflect.New(p.t) + v := rv.Interface().(Parseable) + err = v.Parse(ctx) + if err != nil { + if err == NextMatch { + return nil, nil + } + return nil, err + } + return []reflect.Value{rv.Elem()}, nil +} + +type strct struct { + typ reflect.Type + expr node +} + +func (s *strct) String() string { return stringer(s) } + +func (s *strct) maybeInjectPos(pos lexer.Position, v reflect.Value) { + if f := v.FieldByName("Pos"); f.IsValid() && f.Type() == positionType { + f.Set(reflect.ValueOf(pos)) + } +} + +func (s *strct) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + sv := reflect.New(s.typ).Elem() + t, err := ctx.Peek(0) + if err != nil { + return nil, err + } + s.maybeInjectPos(t.Pos, sv) + if out, err = s.expr.Parse(ctx, sv); err != nil { + _ = ctx.Apply() + return []reflect.Value{sv}, err + } else if out == nil { + return nil, nil + } + return []reflect.Value{sv}, ctx.Apply() +} + +type groupMatchMode int + +const ( + groupMatchOnce groupMatchMode = iota + groupMatchZeroOrOne = iota + groupMatchZeroOrMore = iota + groupMatchOneOrMore = iota + groupMatchNonEmpty = iota +) + +// ( ) - match once +// ( )* - match zero or more times +// ( )+ - match one or more times +// ( )? - match zero or once +// ( )! - must be a non-empty match +// +// The additional modifier "!" forces the content of the group to be non-empty if it does match. +type group struct { + expr node + mode groupMatchMode +} + +func (g *group) String() string { return stringer(g) } +func (g *group) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + // Configure min/max matches. + min := 1 + max := 1 + switch g.mode { + case groupMatchNonEmpty: + out, err = g.expr.Parse(ctx, parent) + if err != nil { + return out, err + } + if len(out) == 0 { + t, _ := ctx.Peek(0) + return out, lexer.Errorf(t.Pos, "sub-expression %s cannot be empty", g) + } + return out, nil + case groupMatchOnce: + return g.expr.Parse(ctx, parent) + case groupMatchZeroOrOne: + min = 0 + case groupMatchZeroOrMore: + min = 0 + max = MaxIterations + case groupMatchOneOrMore: + min = 1 + max = MaxIterations + } + matches := 0 + for ; matches < max; matches++ { + branch := ctx.Branch() + v, err := g.expr.Parse(branch, parent) + out = append(out, v...) + if err != nil { + // Optional part failed to match. + if ctx.Stop(branch) { + return out, err + } + break + } else { + ctx.Accept(branch) + } + if v == nil { + break + } + } + // fmt.Printf("%d < %d < %d: out == nil? %v\n", min, matches, max, out == nil) + t, _ := ctx.Peek(0) + if matches >= MaxIterations { + panic(lexer.Errorf(t.Pos, "too many iterations of %s (> %d)", g, MaxIterations)) + } + if matches < min { + return out, lexer.Errorf(t.Pos, "sub-expression %s must match at least once", g) + } + // The idea here is that something like "a"? is a successful match and that parsing should proceed. + if min == 0 && out == nil { + out = []reflect.Value{} + } + return out, nil +} + +// {"|" } +type disjunction struct { + nodes []node +} + +func (d *disjunction) String() string { return stringer(d) } + +func (d *disjunction) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + var ( + deepestError = 0 + firstError error + firstValues []reflect.Value + ) + for _, a := range d.nodes { + branch := ctx.Branch() + if value, err := a.Parse(branch, parent); err != nil { + // If this branch progressed too far and still didn't match, error out. + if ctx.Stop(branch) { + return value, err + } + // Show the closest error returned. The idea here is that the further the parser progresses + // without error, the more difficult it is to trace the error back to its root. + if err != nil && branch.cursor >= deepestError { + firstError = err + firstValues = value + deepestError = branch.cursor + } + } else if value != nil { + ctx.Accept(branch) + return value, nil + } + } + if firstError != nil { + return firstValues, firstError + } + return nil, nil +} + +// ... +type sequence struct { + head bool + node node + next *sequence +} + +func (s *sequence) String() string { return stringer(s) } + +func (s *sequence) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + for n := s; n != nil; n = n.next { + child, err := n.node.Parse(ctx, parent) + out = append(out, child...) + if err != nil { + return out, err + } + if child == nil { + // Early exit if first value doesn't match, otherwise all values must match. + if n == s { + return nil, nil + } + token, err := ctx.Peek(0) + if err != nil { + return nil, err + } + return out, lexer.Errorf(token.Pos, "unexpected %q (expected %s)", token, n) + } + } + return out, nil +} + +// @ +type capture struct { + field structLexerField + node node +} + +func (c *capture) String() string { return stringer(c) } + +func (c *capture) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + token, err := ctx.Peek(0) + if err != nil { + return nil, err + } + pos := token.Pos + v, err := c.node.Parse(ctx, parent) + if err != nil { + if v != nil { + ctx.Defer(pos, parent, c.field, v) + } + return []reflect.Value{parent}, err + } + if v == nil { + return nil, nil + } + ctx.Defer(pos, parent, c.field, v) + return []reflect.Value{parent}, nil +} + +// - named lexer token reference +type reference struct { + typ rune + identifier string // Used for informational purposes. +} + +func (r *reference) String() string { return stringer(r) } + +func (r *reference) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + token, err := ctx.Peek(0) + if err != nil { + return nil, err + } + if token.Type != r.typ { + return nil, nil + } + _, _ = ctx.Next() + return []reflect.Value{reflect.ValueOf(token.Value)}, nil +} + +// [ ] +type optional struct { + node node +} + +func (o *optional) String() string { return stringer(o) } + +func (o *optional) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + branch := ctx.Branch() + out, err = o.node.Parse(branch, parent) + if err != nil { + // Optional part failed to match. + if ctx.Stop(branch) { + return out, err + } + } else { + ctx.Accept(branch) + } + if out == nil { + out = []reflect.Value{} + } + return out, nil +} + +// { } +type repetition struct { + node node +} + +func (r *repetition) String() string { return stringer(r) } + +// Parse a repetition. Once a repetition is encountered it will always match, so grammars +// should ensure that branches are differentiated prior to the repetition. +func (r *repetition) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + i := 0 + for ; i < MaxIterations; i++ { + branch := ctx.Branch() + v, err := r.node.Parse(branch, parent) + out = append(out, v...) + if err != nil { + // Optional part failed to match. + if ctx.Stop(branch) { + return out, err + } + break + } else { + ctx.Accept(branch) + } + if v == nil { + break + } + } + if i >= MaxIterations { + t, _ := ctx.Peek(0) + panic(lexer.Errorf(t.Pos, "too many iterations of %s (> %d)", r, MaxIterations)) + } + if out == nil { + out = []reflect.Value{} + } + return out, nil +} + +// Match a token literal exactly "..."[:]. +type literal struct { + s string + t rune + tt string // Used for display purposes - symbolic name of t. +} + +func (l *literal) String() string { return stringer(l) } + +func (l *literal) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Value, err error) { + token, err := ctx.Peek(0) + if err != nil { + return nil, err + } + equal := false // nolint: ineffassign + if ctx.caseInsensitive[token.Type] { + equal = strings.EqualFold(token.Value, l.s) + } else { + equal = token.Value == l.s + } + if equal && (l.t == -1 || l.t == token.Type) { + next, err := ctx.Next() + if err != nil { + return nil, err + } + return []reflect.Value{reflect.ValueOf(next.Value)}, nil + } + return nil, nil +} + +// Attempt to transform values to given type. +// +// This will dereference pointers, and attempt to parse strings into integer values, floats, etc. +func conform(t reflect.Type, values []reflect.Value) (out []reflect.Value, err error) { + for _, v := range values { + for t != v.Type() && t.Kind() == reflect.Ptr && v.Kind() != reflect.Ptr { + // This can occur during partial failure. + if !v.CanAddr() { + return + } + v = v.Addr() + } + + // Already of the right kind, don't bother converting. + if v.Kind() == t.Kind() { + out = append(out, v) + continue + } + + kind := t.Kind() + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(v.String(), 0, sizeOfKind(kind)) + if err != nil { + return nil, fmt.Errorf("invalid integer %q: %s", v.String(), err) + } + v = reflect.New(t).Elem() + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, err := strconv.ParseUint(v.String(), 0, sizeOfKind(kind)) + if err != nil { + return nil, fmt.Errorf("invalid integer %q: %s", v.String(), err) + } + v = reflect.New(t).Elem() + v.SetUint(n) + + case reflect.Bool: + v = reflect.ValueOf(true) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(v.String(), sizeOfKind(kind)) + if err != nil { + return nil, fmt.Errorf("invalid integer %q: %s", v.String(), err) + } + v = reflect.New(t).Elem() + v.SetFloat(n) + } + + out = append(out, v) + } + return out, nil +} + +func sizeOfKind(kind reflect.Kind) int { + switch kind { + case reflect.Int8, reflect.Uint8: + return 8 + case reflect.Int16, reflect.Uint16: + return 16 + case reflect.Int32, reflect.Uint32, reflect.Float32: + return 32 + case reflect.Int64, reflect.Uint64, reflect.Float64: + return 64 + case reflect.Int, reflect.Uint: + return strconv.IntSize + } + panic("unsupported kind " + kind.String()) +} + +// Set field. +// +// If field is a pointer the pointer will be set to the value. If field is a string, value will be +// appended. If field is a slice, value will be appended to slice. +// +// For all other types, an attempt will be made to convert the string to the corresponding +// type (int, float32, etc.). +func setField(pos lexer.Position, strct reflect.Value, field structLexerField, fieldValue []reflect.Value) (err error) { // nolint: gocyclo + defer decorate(&err, func() string { return pos.String() + ": " + strct.Type().String() + "." + field.Name }) + + f := strct.FieldByIndex(field.Index) + switch f.Kind() { + case reflect.Slice: + fieldValue, err = conform(f.Type().Elem(), fieldValue) + if err != nil { + return err + } + f.Set(reflect.Append(f, fieldValue...)) + return nil + + case reflect.Ptr: + if f.IsNil() { + fv := reflect.New(f.Type().Elem()).Elem() + f.Set(fv.Addr()) + f = fv + } else { + f = f.Elem() + } + } + + if f.Kind() == reflect.Struct { + if pf := f.FieldByName("Pos"); pf.IsValid() && pf.Type() == positionType { + pf.Set(reflect.ValueOf(pos)) + } + } + + if f.CanAddr() { + if d, ok := f.Addr().Interface().(Capture); ok { + ifv := []string{} + for _, v := range fieldValue { + ifv = append(ifv, v.Interface().(string)) + } + err := d.Capture(ifv) + if err != nil { + return err + } + return nil + } + } + + // Strings concatenate all captured tokens. + if f.Kind() == reflect.String { + fieldValue, err = conform(f.Type(), fieldValue) + if err != nil { + return err + } + for _, v := range fieldValue { + f.Set(reflect.ValueOf(f.String() + v.String()).Convert(f.Type())) + } + return nil + } + + // Coalesce multiple tokens into one. This allows eg. ["-", "10"] to be captured as separate tokens but + // parsed as a single string "-10". + if len(fieldValue) > 1 { + out := []string{} + for _, v := range fieldValue { + out = append(out, v.String()) + } + fieldValue = []reflect.Value{reflect.ValueOf(strings.Join(out, ""))} + } + + fieldValue, err = conform(f.Type(), fieldValue) + if err != nil { + return err + } + + fv := fieldValue[0] + + switch f.Kind() { + // Numeric types will increment if the token can not be coerced. + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if fv.Type() != f.Type() { + f.SetInt(f.Int() + 1) + } else { + f.Set(fv) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if fv.Type() != f.Type() { + f.SetUint(f.Uint() + 1) + } else { + f.Set(fv) + } + + case reflect.Float32, reflect.Float64: + if fv.Type() != f.Type() { + f.SetFloat(f.Float() + 1) + } else { + f.Set(fv) + } + + case reflect.Bool, reflect.Struct: + if fv.Type() != f.Type() { + return fmt.Errorf("value %q is not correct type %s", fv, f.Type()) + } + f.Set(fv) + + default: + return fmt.Errorf("unsupported field type %s for field %s", f.Type(), field.Name) + } + return nil +} + +// Error is an error returned by the parser internally to differentiate from non-Participle errors. +type Error string + +func (e Error) Error() string { return string(e) } diff --git a/vendor/github.com/alecthomas/participle/options.go b/vendor/github.com/alecthomas/participle/options.go new file mode 100644 index 000000000..d3f47d5e2 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/options.go @@ -0,0 +1,39 @@ +package participle + +import ( + "github.com/alecthomas/participle/lexer" +) + +// An Option to modify the behaviour of the Parser. +type Option func(p *Parser) error + +// Lexer is an Option that sets the lexer to use with the given grammar. +func Lexer(def lexer.Definition) Option { + return func(p *Parser) error { + p.lex = def + return nil + } +} + +// UseLookahead allows branch lookahead up to "n" tokens. +// +// If parsing cannot be disambiguated before "n" tokens of lookahead, parsing will fail. +// +// Note that increasing lookahead has a minor performance impact, but also +// reduces the accuracy of error reporting. +func UseLookahead(n int) Option { + return func(p *Parser) error { + p.useLookahead = n + return nil + } +} + +// CaseInsensitive allows the specified token types to be matched case-insensitively. +func CaseInsensitive(tokens ...string) Option { + return func(p *Parser) error { + for _, token := range tokens { + p.caseInsensitive[token] = true + } + return nil + } +} diff --git a/vendor/github.com/alecthomas/participle/parser.go b/vendor/github.com/alecthomas/participle/parser.go new file mode 100644 index 000000000..4682d267d --- /dev/null +++ b/vendor/github.com/alecthomas/participle/parser.go @@ -0,0 +1,229 @@ +package participle + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strings" + + "github.com/alecthomas/participle/lexer" +) + +// A Parser for a particular grammar and lexer. +type Parser struct { + root node + lex lexer.Definition + typ reflect.Type + useLookahead int + caseInsensitive map[string]bool + mappers []mapperByToken +} + +// MustBuild calls Build(grammar, options...) and panics if an error occurs. +func MustBuild(grammar interface{}, options ...Option) *Parser { + parser, err := Build(grammar, options...) + if err != nil { + panic(err) + } + return parser +} + +// Build constructs a parser for the given grammar. +// +// If "Lexer()" is not provided as an option, a default lexer based on text/scanner will be used. This scans typical Go- +// like tokens. +// +// See documentation for details +func Build(grammar interface{}, options ...Option) (parser *Parser, err error) { + // Configure Parser struct with defaults + options. + p := &Parser{ + lex: lexer.TextScannerLexer, + caseInsensitive: map[string]bool{}, + useLookahead: 1, + } + for _, option := range options { + if option == nil { + return nil, fmt.Errorf("nil Option passed, signature has changed; " + + "if you intended to provide a custom Lexer, try participle.Build(grammar, participle.Lexer(lexer))") + } + if err = option(p); err != nil { + return nil, err + } + } + + if len(p.mappers) > 0 { + mappers := map[rune][]Mapper{} + symbols := p.lex.Symbols() + for _, mapper := range p.mappers { + if len(mapper.symbols) == 0 { + mappers[lexer.EOF] = append(mappers[lexer.EOF], mapper.mapper) + } else { + for _, symbol := range mapper.symbols { + if rn, ok := symbols[symbol]; !ok { + return nil, fmt.Errorf("mapper %#v uses unknown token %q", mapper, symbol) + } else { // nolint: golint + mappers[rn] = append(mappers[rn], mapper.mapper) + } + } + } + } + p.lex = &mappingLexerDef{p.lex, func(t lexer.Token) (lexer.Token, error) { + combined := make([]Mapper, 0, len(mappers[t.Type])+len(mappers[lexer.EOF])) + combined = append(combined, mappers[lexer.EOF]...) + combined = append(combined, mappers[t.Type]...) + + var err error + for _, m := range combined { + t, err = m(t) + if err != nil { + return t, err + } + } + return t, nil + }} + } + + context := newGeneratorContext(p.lex) + v := reflect.ValueOf(grammar) + if v.Kind() == reflect.Interface { + v = v.Elem() + } + p.typ = v.Type() + p.root, err = context.parseType(p.typ) + if err != nil { + return nil, err + } + return p, nil +} + +// Lex uses the parser's lexer to tokenise input. +func (p *Parser) Lex(r io.Reader) ([]lexer.Token, error) { + lex, err := p.lex.Lex(r) + if err != nil { + return nil, err + } + return lexer.ConsumeAll(lex) +} + +// Parse from r into grammar v which must be of the same type as the grammar passed to +// participle.Build(). +func (p *Parser) Parse(r io.Reader, v interface{}) (err error) { + rv := reflect.ValueOf(v) + if rv.Kind() == reflect.Interface { + rv = rv.Elem() + } + var stream reflect.Value + if rv.Kind() == reflect.Chan { + stream = rv + rt := rv.Type().Elem() + rv = reflect.New(rt).Elem() + } + rt := rv.Type() + if rt != p.typ { + return fmt.Errorf("must parse into value of type %s not %T", p.typ, v) + } + baseLexer, err := p.lex.Lex(r) + if err != nil { + return err + } + lex := lexer.Upgrade(baseLexer) + caseInsensitive := map[rune]bool{} + for sym, rn := range p.lex.Symbols() { + if p.caseInsensitive[sym] { + caseInsensitive[rn] = true + } + } + ctx, err := newParseContext(lex, p.useLookahead, caseInsensitive) + if err != nil { + return err + } + // If the grammar implements Parseable, use it. + if parseable, ok := v.(Parseable); ok { + return p.rootParseable(ctx, parseable) + } + if rt.Kind() != reflect.Ptr || rt.Elem().Kind() != reflect.Struct { + return fmt.Errorf("target must be a pointer to a struct, not %s", rt) + } + if stream.IsValid() { + return p.parseStreaming(ctx, stream) + } + return p.parseOne(ctx, rv) +} + +func (p *Parser) parseStreaming(ctx *parseContext, rv reflect.Value) error { + t := rv.Type().Elem().Elem() + for { + if token, _ := ctx.Peek(0); token.EOF() { + rv.Close() + return nil + } + v := reflect.New(t) + if err := p.parseInto(ctx, v); err != nil { + return err + } + rv.Send(v) + } +} + +func (p *Parser) parseOne(ctx *parseContext, rv reflect.Value) error { + err := p.parseInto(ctx, rv) + if err != nil { + return err + } + token, err := ctx.Peek(0) + if err != nil { + return err + } else if !token.EOF() { + return lexer.Errorf(token.Pos, "unexpected trailing token %q", token) + } + return nil +} + +func (p *Parser) parseInto(ctx *parseContext, rv reflect.Value) error { + if rv.IsNil() { + return fmt.Errorf("target must be a non-nil pointer to a struct, but is a nil %s", rv.Type()) + } + pv, err := p.root.Parse(ctx, rv.Elem()) + if len(pv) > 0 && pv[0].Type() == rv.Elem().Type() { + rv.Elem().Set(reflect.Indirect(pv[0])) + } + if err != nil { + return err + } + if pv == nil { + token, _ := ctx.Peek(0) + return lexer.Errorf(token.Pos, "invalid syntax") + } + return nil +} + +func (p *Parser) rootParseable(lex lexer.PeekingLexer, parseable Parseable) error { + peek, err := lex.Peek(0) + if err != nil { + return err + } + err = parseable.Parse(lex) + if err == NextMatch { + return lexer.Errorf(peek.Pos, "invalid syntax") + } + if err == nil && !peek.EOF() { + return lexer.Errorf(peek.Pos, "unexpected token %q", peek) + } + return err +} + +// ParseString is a convenience around Parse(). +func (p *Parser) ParseString(s string, v interface{}) error { + return p.Parse(strings.NewReader(s), v) +} + +// ParseBytes is a convenience around Parse(). +func (p *Parser) ParseBytes(b []byte, v interface{}) error { + return p.Parse(bytes.NewReader(b), v) +} + +// String representation of the grammar. +func (p *Parser) String() string { + return stringern(p.root, 128) +} diff --git a/vendor/github.com/alecthomas/participle/stringer.go b/vendor/github.com/alecthomas/participle/stringer.go new file mode 100644 index 000000000..4aebcecc9 --- /dev/null +++ b/vendor/github.com/alecthomas/participle/stringer.go @@ -0,0 +1,118 @@ +package participle + +import ( + "bytes" + "fmt" + "strings" + + "github.com/alecthomas/participle/lexer" +) + +type stringerVisitor struct { + bytes.Buffer + seen map[node]bool +} + +func stringern(n node, depth int) string { + v := &stringerVisitor{seen: map[node]bool{}} + v.visit(n, depth, false) + return v.String() +} + +func stringer(n node) string { + return stringern(n, 1) +} + +func (s *stringerVisitor) visit(n node, depth int, disjunctions bool) { + if s.seen[n] || depth <= 0 { + fmt.Fprintf(s, "...") + return + } + s.seen[n] = true + + switch n := n.(type) { + case *disjunction: + for i, c := range n.nodes { + if i > 0 { + fmt.Fprint(s, " | ") + } + s.visit(c, depth, disjunctions || len(n.nodes) > 1) + } + + case *strct: + s.visit(n.expr, depth, disjunctions) + + case *sequence: + c := n + for i := 0; c != nil && depth-i > 0; c, i = c.next, i+1 { + if c != n { + fmt.Fprint(s, " ") + } + s.visit(c.node, depth-i, disjunctions) + } + if c != nil { + fmt.Fprint(s, " ...") + } + + case *parseable: + fmt.Fprintf(s, "<%s>", strings.ToLower(n.t.Name())) + + case *capture: + if _, ok := n.node.(*parseable); ok { + fmt.Fprintf(s, "<%s>", strings.ToLower(n.field.Name)) + } else { + if n.node == nil { + fmt.Fprintf(s, "<%s>", strings.ToLower(n.field.Name)) + } else { + s.visit(n.node, depth, disjunctions) + } + } + + case *reference: + fmt.Fprintf(s, "<%s>", strings.ToLower(n.identifier)) + + case *optional: + fmt.Fprint(s, "[ ") + s.visit(n.node, depth, disjunctions) + fmt.Fprint(s, " ]") + + case *repetition: + fmt.Fprint(s, "{ ") + s.visit(n.node, depth, disjunctions) + fmt.Fprint(s, " }") + + case *literal: + fmt.Fprintf(s, "%q", n.s) + if n.t != lexer.EOF && n.s == "" { + fmt.Fprintf(s, ":%s", n.tt) + } + + case *group: + fmt.Fprint(s, "(") + if child, ok := n.expr.(*group); ok && child.mode == groupMatchOnce { + s.visit(child.expr, depth, disjunctions) + } else if child, ok := n.expr.(*capture); ok { + if grandchild, ok := child.node.(*group); ok && grandchild.mode == groupMatchOnce { + s.visit(grandchild.expr, depth, disjunctions) + } else { + s.visit(n.expr, depth, disjunctions) + } + } else { + s.visit(n.expr, depth, disjunctions) + } + fmt.Fprint(s, ")") + switch n.mode { + case groupMatchNonEmpty: + fmt.Fprintf(s, "!") + case groupMatchZeroOrOne: + fmt.Fprintf(s, "?") + case groupMatchZeroOrMore: + fmt.Fprintf(s, "*") + case groupMatchOneOrMore: + fmt.Fprintf(s, "+") + } + + default: + panic("unsupported") + } +} diff --git a/vendor/github.com/alecthomas/participle/struct.go b/vendor/github.com/alecthomas/participle/struct.go new file mode 100644 index 000000000..cd343e64b --- /dev/null +++ b/vendor/github.com/alecthomas/participle/struct.go @@ -0,0 +1,126 @@ +package participle + +import ( + "fmt" + "reflect" + + "github.com/alecthomas/participle/lexer" +) + +// A structLexer lexes over the tags of struct fields while tracking the current field. +type structLexer struct { + s reflect.Type + field int + indexes [][]int + lexer lexer.PeekingLexer +} + +func lexStruct(s reflect.Type) (*structLexer, error) { + indexes, err := collectFieldIndexes(s) + if err != nil { + return nil, err + } + slex := &structLexer{ + s: s, + indexes: indexes, + } + if len(slex.indexes) > 0 { + tag := fieldLexerTag(slex.Field().StructField) + slex.lexer = lexer.Upgrade(lexer.LexString(tag)) + } + return slex, nil +} + +// NumField returns the number of fields in the struct associated with this structLexer. +func (s *structLexer) NumField() int { + return len(s.indexes) +} + +type structLexerField struct { + reflect.StructField + Index []int +} + +// Field returns the field associated with the current token. +func (s *structLexer) Field() structLexerField { + return s.GetField(s.field) +} + +func (s *structLexer) GetField(field int) structLexerField { + if field >= len(s.indexes) { + field = len(s.indexes) - 1 + } + return structLexerField{ + StructField: s.s.FieldByIndex(s.indexes[field]), + Index: s.indexes[field], + } +} + +func (s *structLexer) Peek() (lexer.Token, error) { + field := s.field + lex := s.lexer + for { + token, err := lex.Peek(0) + if err != nil { + return token, err + } + if !token.EOF() { + token.Pos.Line = field + 1 + return token, nil + } + field++ + if field >= s.NumField() { + return lexer.EOFToken(token.Pos), nil + } + tag := fieldLexerTag(s.GetField(field).StructField) + lex = lexer.Upgrade(lexer.LexString(tag)) + } +} + +func (s *structLexer) Next() (lexer.Token, error) { + token, err := s.lexer.Next() + if err != nil { + return token, err + } + if !token.EOF() { + token.Pos.Line = s.field + 1 + return token, nil + } + if s.field+1 >= s.NumField() { + return lexer.EOFToken(token.Pos), nil + } + s.field++ + tag := fieldLexerTag(s.Field().StructField) + s.lexer = lexer.Upgrade(lexer.LexString(tag)) + return s.Next() +} + +func fieldLexerTag(field reflect.StructField) string { + if tag, ok := field.Tag.Lookup("parser"); ok { + return tag + } + return string(field.Tag) +} + +// Recursively collect flattened indices for top-level fields and embedded fields. +func collectFieldIndexes(s reflect.Type) (out [][]int, err error) { + if s.Kind() != reflect.Struct { + return nil, fmt.Errorf("expected a struct but got %q", s) + } + defer decorate(&err, s.String) + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + if f.Anonymous { + children, err := collectFieldIndexes(f.Type) + if err != nil { + return nil, err + } + for _, idx := range children { + out = append(out, append(f.Index, idx...)) + } + } else if fieldLexerTag(f) != "" { + out = append(out, f.Index) + } + } + return +} diff --git a/vendor/github.com/minio/parquet-go/parquet.go b/vendor/github.com/minio/parquet-go/parquet.go index d9719cfee..d9d4339f2 100644 --- a/vendor/github.com/minio/parquet-go/parquet.go +++ b/vendor/github.com/minio/parquet-go/parquet.go @@ -88,6 +88,7 @@ type File struct { rowGroups []*parquet.RowGroup rowGroupIndex int + nameList []string columnNames set.StringSet columns map[string]*column rowIndex int64 @@ -100,16 +101,23 @@ func Open(getReaderFunc GetReaderFunc, columnNames set.StringSet) (*File, error) return nil, err } + nameList := []string{} + schemaElements := fileMeta.GetSchema() + for _, element := range schemaElements { + nameList = append(nameList, element.Name) + } + return &File{ getReaderFunc: getReaderFunc, rowGroups: fileMeta.GetRowGroups(), - schemaElements: fileMeta.GetSchema(), + schemaElements: schemaElements, + nameList: nameList, columnNames: columnNames, }, nil } // Read - reads single record. -func (file *File) Read() (record map[string]Value, err error) { +func (file *File) Read() (record *Record, err error) { if file.rowGroupIndex >= len(file.rowGroups) { return nil, io.EOF } @@ -134,10 +142,10 @@ func (file *File) Read() (record map[string]Value, err error) { return file.Read() } - record = make(map[string]Value) + record = newRecord(file.nameList) for name := range file.columns { value, valueType := file.columns[name].read() - record[name] = Value{value, valueType} + record.set(name, Value{value, valueType}) } file.rowIndex++ diff --git a/vendor/github.com/minio/parquet-go/record.go b/vendor/github.com/minio/parquet-go/record.go new file mode 100644 index 000000000..6d25632f3 --- /dev/null +++ b/vendor/github.com/minio/parquet-go/record.go @@ -0,0 +1,70 @@ +/* + * Minio Cloud Storage, (C) 2019 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package parquet + +import ( + "fmt" + "strings" +) + +// Record - ordered parquet record. +type Record struct { + nameList []string + nameValueMap map[string]Value +} + +// String - returns string representation of this record. +func (r *Record) String() string { + values := []string{} + r.Range(func(name string, value Value) bool { + values = append(values, fmt.Sprintf("%v:%v", name, value)) + return true + }) + + return "map[" + strings.Join(values, " ") + "]" +} + +func (r *Record) set(name string, value Value) { + r.nameValueMap[name] = value +} + +// Get - returns Value of name. +func (r *Record) Get(name string) (Value, bool) { + value, ok := r.nameValueMap[name] + return value, ok +} + +// Range - calls f sequentially for each name and value present in the record. If f returns false, range stops the iteration. +func (r *Record) Range(f func(name string, value Value) bool) { + for _, name := range r.nameList { + value, ok := r.nameValueMap[name] + if !ok { + continue + } + + if !f(name, value) { + break + } + } +} + +func newRecord(nameList []string) *Record { + return &Record{ + nameList: nameList, + nameValueMap: make(map[string]Value), + } +} diff --git a/vendor/github.com/xwb1989/sqlparser/CONTRIBUTORS.md b/vendor/github.com/xwb1989/sqlparser/CONTRIBUTORS.md deleted file mode 100644 index a44885cd9..000000000 --- a/vendor/github.com/xwb1989/sqlparser/CONTRIBUTORS.md +++ /dev/null @@ -1,9 +0,0 @@ -This project is originally a fork of [https://github.com/youtube/vitess](https://github.com/youtube/vitess) -Copyright Google Inc - -# Contributors -Wenbin Xiao 2015 -Started this project and maintained it. - -Andrew Brampton 2017 -Merged in multiple upstream fixes/changes. \ No newline at end of file diff --git a/vendor/github.com/xwb1989/sqlparser/LICENSE.md b/vendor/github.com/xwb1989/sqlparser/LICENSE.md deleted file mode 100644 index f49a4e16e..000000000 --- a/vendor/github.com/xwb1989/sqlparser/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. \ No newline at end of file diff --git a/vendor/github.com/xwb1989/sqlparser/Makefile b/vendor/github.com/xwb1989/sqlparser/Makefile deleted file mode 100644 index 215f422e6..000000000 --- a/vendor/github.com/xwb1989/sqlparser/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -MAKEFLAGS = -s - -sql.go: sql.y - goyacc -o sql.go sql.y - gofmt -w sql.go - -clean: - rm -f y.output sql.go diff --git a/vendor/github.com/xwb1989/sqlparser/README.md b/vendor/github.com/xwb1989/sqlparser/README.md deleted file mode 100644 index 58d475967..000000000 --- a/vendor/github.com/xwb1989/sqlparser/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# sqlparser [![Build Status](https://img.shields.io/travis/xwb1989/sqlparser.svg)](https://travis-ci.org/xwb1989/sqlparser) [![Coverage](https://img.shields.io/coveralls/xwb1989/sqlparser.svg)](https://coveralls.io/github/xwb1989/sqlparser) [![Report card](https://goreportcard.com/badge/github.com/xwb1989/sqlparser)](https://goreportcard.com/report/github.com/xwb1989/sqlparser) [![GoDoc](https://godoc.org/github.com/xwb1989/sqlparser?status.svg)](https://godoc.org/github.com/xwb1989/sqlparser) - -Go package for parsing MySQL SQL queries. - -## Notice - -The backbone of this repo is extracted from [vitessio/vitess](https://github.com/vitessio/vitess). - -Inside vitessio/vitess there is a very nicely written sql parser. However as it's not a self-contained application, I created this one. -It applies the same LICENSE as vitessio/vitess. - -## Usage - -```go -import ( - "github.com/xwb1989/sqlparser" -) -``` - -Then use: - -```go -sql := "SELECT * FROM table WHERE a = 'abc'" -stmt, err := sqlparser.Parse(sql) -if err != nil { - // Do something with the err -} - -// Otherwise do something with stmt -switch stmt := stmt.(type) { -case *sqlparser.Select: - _ = stmt -case *sqlparser.Insert: -} -``` - -Alternative to read many queries from a io.Reader: - -```go -r := strings.NewReader("INSERT INTO table1 VALUES (1, 'a'); INSERT INTO table2 VALUES (3, 4);") - -tokens := sqlparser.NewTokenizer(r) -for { - stmt, err := sqlparser.ParseNext(tokens) - if err == io.EOF { - break - } - // Do something with stmt or err. -} -``` - -See [parse_test.go](https://github.com/xwb1989/sqlparser/blob/master/parse_test.go) for more examples, or read the [godoc](https://godoc.org/github.com/xwb1989/sqlparser). - - -## Porting Instructions - -You only need the below if you plan to try and keep this library up to date with [vitessio/vitess](https://github.com/vitessio/vitess). - -### Keeping up to date - -```bash -shopt -s nullglob -VITESS=${GOPATH?}/src/vitess.io/vitess/go/ -XWB1989=${GOPATH?}/src/github.com/xwb1989/sqlparser/ - -# Create patches for everything that changed -LASTIMPORT=1b7879cb91f1dfe1a2dfa06fea96e951e3a7aec5 -for path in ${VITESS?}/{vt/sqlparser,sqltypes,bytes2,hack}; do - cd ${path} - git format-patch ${LASTIMPORT?} . -done; - -# Apply patches to the dependencies -cd ${XWB1989?} -git am --directory dependency -p2 ${VITESS?}/{sqltypes,bytes2,hack}/*.patch - -# Apply the main patches to the repo -cd ${XWB1989?} -git am -p4 ${VITESS?}/vt/sqlparser/*.patch - -# If you encounter diff failures, manually fix them with -patch -p4 < .git/rebase-apply/patch -... -git add name_of_files -git am --continue - -# Cleanup -rm ${VITESS?}/{sqltypes,bytes2,hack}/*.patch ${VITESS?}/*.patch - -# and Finally update the LASTIMPORT in this README. -``` - -### Fresh install - -TODO: Change these instructions to use git to copy the files, that'll make later patching easier. - -```bash -VITESS=${GOPATH?}/src/vitess.io/vitess/go/ -XWB1989=${GOPATH?}/src/github.com/xwb1989/sqlparser/ - -cd ${XWB1989?} - -# Copy all the code -cp -pr ${VITESS?}/vt/sqlparser/ . -cp -pr ${VITESS?}/sqltypes dependency -cp -pr ${VITESS?}/bytes2 dependency -cp -pr ${VITESS?}/hack dependency - -# Delete some code we haven't ported -rm dependency/sqltypes/arithmetic.go dependency/sqltypes/arithmetic_test.go dependency/sqltypes/event_token.go dependency/sqltypes/event_token_test.go dependency/sqltypes/proto3.go dependency/sqltypes/proto3_test.go dependency/sqltypes/query_response.go dependency/sqltypes/result.go dependency/sqltypes/result_test.go - -# Some automated fixes - -# Fix imports -sed -i '.bak' 's_vitess.io/vitess/go/vt/proto/query_github.com/xwb1989/sqlparser/dependency/querypb_g' *.go dependency/sqltypes/*.go -sed -i '.bak' 's_vitess.io/vitess/go/_github.com/xwb1989/sqlparser/dependency/_g' *.go dependency/sqltypes/*.go - -# Copy the proto, but basically drop everything we don't want -cp -pr ${VITESS?}/vt/proto/query dependency/querypb - -sed -i '.bak' 's_.*Descriptor.*__g' dependency/querypb/*.go -sed -i '.bak' 's_.*ProtoMessage.*__g' dependency/querypb/*.go - -sed -i '.bak' 's/proto.CompactTextString(m)/"TODO"/g' dependency/querypb/*.go -sed -i '.bak' 's/proto.EnumName/EnumName/g' dependency/querypb/*.go - -sed -i '.bak' 's/proto.Equal/reflect.DeepEqual/g' dependency/sqltypes/*.go - -# Remove the error library -sed -i '.bak' 's/vterrors.Errorf([^,]*, /fmt.Errorf(/g' *.go dependency/sqltypes/*.go -sed -i '.bak' 's/vterrors.New([^,]*, /errors.New(/g' *.go dependency/sqltypes/*.go -``` - -### Testing - -```bash -VITESS=${GOPATH?}/src/vitess.io/vitess/go/ -XWB1989=${GOPATH?}/src/github.com/xwb1989/sqlparser/ - -cd ${XWB1989?} - -# Test, fix and repeat -go test ./... - -# Finally make some diffs (for later reference) -diff -u ${VITESS?}/sqltypes/ ${XWB1989?}/dependency/sqltypes/ > ${XWB1989?}/patches/sqltypes.patch -diff -u ${VITESS?}/bytes2/ ${XWB1989?}/dependency/bytes2/ > ${XWB1989?}/patches/bytes2.patch -diff -u ${VITESS?}/vt/proto/query/ ${XWB1989?}/dependency/querypb/ > ${XWB1989?}/patches/querypb.patch -diff -u ${VITESS?}/vt/sqlparser/ ${XWB1989?}/ > ${XWB1989?}/patches/sqlparser.patch -``` \ No newline at end of file diff --git a/vendor/github.com/xwb1989/sqlparser/analyzer.go b/vendor/github.com/xwb1989/sqlparser/analyzer.go deleted file mode 100644 index 95f97d355..000000000 --- a/vendor/github.com/xwb1989/sqlparser/analyzer.go +++ /dev/null @@ -1,343 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -// analyzer.go contains utility analysis functions. - -import ( - "errors" - "fmt" - "strconv" - "strings" - "unicode" - - "github.com/xwb1989/sqlparser/dependency/sqltypes" -) - -// These constants are used to identify the SQL statement type. -const ( - StmtSelect = iota - StmtStream - StmtInsert - StmtReplace - StmtUpdate - StmtDelete - StmtDDL - StmtBegin - StmtCommit - StmtRollback - StmtSet - StmtShow - StmtUse - StmtOther - StmtUnknown - StmtComment -) - -// Preview analyzes the beginning of the query using a simpler and faster -// textual comparison to identify the statement type. -func Preview(sql string) int { - trimmed := StripLeadingComments(sql) - - firstWord := trimmed - if end := strings.IndexFunc(trimmed, unicode.IsSpace); end != -1 { - firstWord = trimmed[:end] - } - firstWord = strings.TrimLeftFunc(firstWord, func(r rune) bool { return !unicode.IsLetter(r) }) - // Comparison is done in order of priority. - loweredFirstWord := strings.ToLower(firstWord) - switch loweredFirstWord { - case "select": - return StmtSelect - case "stream": - return StmtStream - case "insert": - return StmtInsert - case "replace": - return StmtReplace - case "update": - return StmtUpdate - case "delete": - return StmtDelete - } - // For the following statements it is not sufficient to rely - // on loweredFirstWord. This is because they are not statements - // in the grammar and we are relying on Preview to parse them. - // For instance, we don't want: "BEGIN JUNK" to be parsed - // as StmtBegin. - trimmedNoComments, _ := SplitMarginComments(trimmed) - switch strings.ToLower(trimmedNoComments) { - case "begin", "start transaction": - return StmtBegin - case "commit": - return StmtCommit - case "rollback": - return StmtRollback - } - switch loweredFirstWord { - case "create", "alter", "rename", "drop", "truncate": - return StmtDDL - case "set": - return StmtSet - case "show": - return StmtShow - case "use": - return StmtUse - case "analyze", "describe", "desc", "explain", "repair", "optimize": - return StmtOther - } - if strings.Index(trimmed, "/*!") == 0 { - return StmtComment - } - return StmtUnknown -} - -// StmtType returns the statement type as a string -func StmtType(stmtType int) string { - switch stmtType { - case StmtSelect: - return "SELECT" - case StmtStream: - return "STREAM" - case StmtInsert: - return "INSERT" - case StmtReplace: - return "REPLACE" - case StmtUpdate: - return "UPDATE" - case StmtDelete: - return "DELETE" - case StmtDDL: - return "DDL" - case StmtBegin: - return "BEGIN" - case StmtCommit: - return "COMMIT" - case StmtRollback: - return "ROLLBACK" - case StmtSet: - return "SET" - case StmtShow: - return "SHOW" - case StmtUse: - return "USE" - case StmtOther: - return "OTHER" - default: - return "UNKNOWN" - } -} - -// IsDML returns true if the query is an INSERT, UPDATE or DELETE statement. -func IsDML(sql string) bool { - switch Preview(sql) { - case StmtInsert, StmtReplace, StmtUpdate, StmtDelete: - return true - } - return false -} - -// GetTableName returns the table name from the SimpleTableExpr -// only if it's a simple expression. Otherwise, it returns "". -func GetTableName(node SimpleTableExpr) TableIdent { - if n, ok := node.(TableName); ok && n.Qualifier.IsEmpty() { - return n.Name - } - // sub-select or '.' expression - return NewTableIdent("") -} - -// IsColName returns true if the Expr is a *ColName. -func IsColName(node Expr) bool { - _, ok := node.(*ColName) - return ok -} - -// IsValue returns true if the Expr is a string, integral or value arg. -// NULL is not considered to be a value. -func IsValue(node Expr) bool { - switch v := node.(type) { - case *SQLVal: - switch v.Type { - case StrVal, HexVal, IntVal, ValArg: - return true - } - } - return false -} - -// IsNull returns true if the Expr is SQL NULL -func IsNull(node Expr) bool { - switch node.(type) { - case *NullVal: - return true - } - return false -} - -// IsSimpleTuple returns true if the Expr is a ValTuple that -// contains simple values or if it's a list arg. -func IsSimpleTuple(node Expr) bool { - switch vals := node.(type) { - case ValTuple: - for _, n := range vals { - if !IsValue(n) { - return false - } - } - return true - case ListArg: - return true - } - // It's a subquery - return false -} - -// NewPlanValue builds a sqltypes.PlanValue from an Expr. -func NewPlanValue(node Expr) (sqltypes.PlanValue, error) { - switch node := node.(type) { - case *SQLVal: - switch node.Type { - case ValArg: - return sqltypes.PlanValue{Key: string(node.Val[1:])}, nil - case IntVal: - n, err := sqltypes.NewIntegral(string(node.Val)) - if err != nil { - return sqltypes.PlanValue{}, fmt.Errorf("%v", err) - } - return sqltypes.PlanValue{Value: n}, nil - case StrVal: - return sqltypes.PlanValue{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, node.Val)}, nil - case HexVal: - v, err := node.HexDecode() - if err != nil { - return sqltypes.PlanValue{}, fmt.Errorf("%v", err) - } - return sqltypes.PlanValue{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, v)}, nil - } - case ListArg: - return sqltypes.PlanValue{ListKey: string(node[2:])}, nil - case ValTuple: - pv := sqltypes.PlanValue{ - Values: make([]sqltypes.PlanValue, 0, len(node)), - } - for _, val := range node { - innerpv, err := NewPlanValue(val) - if err != nil { - return sqltypes.PlanValue{}, err - } - if innerpv.ListKey != "" || innerpv.Values != nil { - return sqltypes.PlanValue{}, errors.New("unsupported: nested lists") - } - pv.Values = append(pv.Values, innerpv) - } - return pv, nil - case *NullVal: - return sqltypes.PlanValue{}, nil - } - return sqltypes.PlanValue{}, fmt.Errorf("expression is too complex '%v'", String(node)) -} - -// StringIn is a convenience function that returns -// true if str matches any of the values. -func StringIn(str string, values ...string) bool { - for _, val := range values { - if str == val { - return true - } - } - return false -} - -// SetKey is the extracted key from one SetExpr -type SetKey struct { - Key string - Scope string -} - -// ExtractSetValues returns a map of key-value pairs -// if the query is a SET statement. Values can be bool, int64 or string. -// Since set variable names are case insensitive, all keys are returned -// as lower case. -func ExtractSetValues(sql string) (keyValues map[SetKey]interface{}, scope string, err error) { - stmt, err := Parse(sql) - if err != nil { - return nil, "", err - } - setStmt, ok := stmt.(*Set) - if !ok { - return nil, "", fmt.Errorf("ast did not yield *sqlparser.Set: %T", stmt) - } - result := make(map[SetKey]interface{}) - for _, expr := range setStmt.Exprs { - scope := SessionStr - key := expr.Name.Lowered() - switch { - case strings.HasPrefix(key, "@@global."): - scope = GlobalStr - key = strings.TrimPrefix(key, "@@global.") - case strings.HasPrefix(key, "@@session."): - key = strings.TrimPrefix(key, "@@session.") - case strings.HasPrefix(key, "@@"): - key = strings.TrimPrefix(key, "@@") - } - - if strings.HasPrefix(expr.Name.Lowered(), "@@") { - if setStmt.Scope != "" && scope != "" { - return nil, "", fmt.Errorf("unsupported in set: mixed using of variable scope") - } - _, out := NewStringTokenizer(key).Scan() - key = string(out) - } - - setKey := SetKey{ - Key: key, - Scope: scope, - } - - switch expr := expr.Expr.(type) { - case *SQLVal: - switch expr.Type { - case StrVal: - result[setKey] = strings.ToLower(string(expr.Val)) - case IntVal: - num, err := strconv.ParseInt(string(expr.Val), 0, 64) - if err != nil { - return nil, "", err - } - result[setKey] = num - default: - return nil, "", fmt.Errorf("invalid value type: %v", String(expr)) - } - case BoolVal: - var val int64 - if expr { - val = 1 - } - result[setKey] = val - case *ColName: - result[setKey] = expr.Name.String() - case *NullVal: - result[setKey] = nil - case *Default: - result[setKey] = "default" - default: - return nil, "", fmt.Errorf("invalid syntax: %s", String(expr)) - } - } - return result, strings.ToLower(setStmt.Scope), nil -} diff --git a/vendor/github.com/xwb1989/sqlparser/ast.go b/vendor/github.com/xwb1989/sqlparser/ast.go deleted file mode 100644 index c3a0d0837..000000000 --- a/vendor/github.com/xwb1989/sqlparser/ast.go +++ /dev/null @@ -1,3450 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "fmt" - "io" - "log" - "strings" - - "github.com/xwb1989/sqlparser/dependency/querypb" - "github.com/xwb1989/sqlparser/dependency/sqltypes" -) - -// Instructions for creating new types: If a type -// needs to satisfy an interface, declare that function -// along with that interface. This will help users -// identify the list of types to which they can assert -// those interfaces. -// If the member of a type has a string with a predefined -// list of values, declare those values as const following -// the type. -// For interfaces that define dummy functions to consolidate -// a set of types, define the function as iTypeName. -// This will help avoid name collisions. - -// Parse parses the SQL in full and returns a Statement, which -// is the AST representation of the query. If a DDL statement -// is partially parsed but still contains a syntax error, the -// error is ignored and the DDL is returned anyway. -func Parse(sql string) (Statement, error) { - tokenizer := NewStringTokenizer(sql) - if yyParse(tokenizer) != 0 { - if tokenizer.partialDDL != nil { - log.Printf("ignoring error parsing DDL '%s': %v", sql, tokenizer.LastError) - tokenizer.ParseTree = tokenizer.partialDDL - return tokenizer.ParseTree, nil - } - return nil, tokenizer.LastError - } - return tokenizer.ParseTree, nil -} - -// ParseStrictDDL is the same as Parse except it errors on -// partially parsed DDL statements. -func ParseStrictDDL(sql string) (Statement, error) { - tokenizer := NewStringTokenizer(sql) - if yyParse(tokenizer) != 0 { - return nil, tokenizer.LastError - } - return tokenizer.ParseTree, nil -} - -// ParseNext parses a single SQL statement from the tokenizer -// returning a Statement which is the AST representation of the query. -// The tokenizer will always read up to the end of the statement, allowing for -// the next call to ParseNext to parse any subsequent SQL statements. When -// there are no more statements to parse, a error of io.EOF is returned. -func ParseNext(tokenizer *Tokenizer) (Statement, error) { - if tokenizer.lastChar == ';' { - tokenizer.next() - tokenizer.skipBlank() - } - if tokenizer.lastChar == eofChar { - return nil, io.EOF - } - - tokenizer.reset() - tokenizer.multi = true - if yyParse(tokenizer) != 0 { - if tokenizer.partialDDL != nil { - tokenizer.ParseTree = tokenizer.partialDDL - return tokenizer.ParseTree, nil - } - return nil, tokenizer.LastError - } - return tokenizer.ParseTree, nil -} - -// SplitStatement returns the first sql statement up to either a ; or EOF -// and the remainder from the given buffer -func SplitStatement(blob string) (string, string, error) { - tokenizer := NewStringTokenizer(blob) - tkn := 0 - for { - tkn, _ = tokenizer.Scan() - if tkn == 0 || tkn == ';' || tkn == eofChar { - break - } - } - if tokenizer.LastError != nil { - return "", "", tokenizer.LastError - } - if tkn == ';' { - return blob[:tokenizer.Position-2], blob[tokenizer.Position-1:], nil - } - return blob, "", nil -} - -// SplitStatementToPieces split raw sql statement that may have multi sql pieces to sql pieces -// returns the sql pieces blob contains; or error if sql cannot be parsed -func SplitStatementToPieces(blob string) (pieces []string, err error) { - pieces = make([]string, 0, 16) - tokenizer := NewStringTokenizer(blob) - - tkn := 0 - var stmt string - stmtBegin := 0 - for { - tkn, _ = tokenizer.Scan() - if tkn == ';' { - stmt = blob[stmtBegin : tokenizer.Position-2] - pieces = append(pieces, stmt) - stmtBegin = tokenizer.Position - 1 - - } else if tkn == 0 || tkn == eofChar { - blobTail := tokenizer.Position - 2 - - if stmtBegin < blobTail { - stmt = blob[stmtBegin : blobTail+1] - pieces = append(pieces, stmt) - } - break - } - } - - err = tokenizer.LastError - return -} - -// SQLNode defines the interface for all nodes -// generated by the parser. -type SQLNode interface { - Format(buf *TrackedBuffer) - // walkSubtree calls visit on all underlying nodes - // of the subtree, but not the current one. Walking - // must be interrupted if visit returns an error. - walkSubtree(visit Visit) error -} - -// Visit defines the signature of a function that -// can be used to visit all nodes of a parse tree. -type Visit func(node SQLNode) (kontinue bool, err error) - -// Walk calls visit on every node. -// If visit returns true, the underlying nodes -// are also visited. If it returns an error, walking -// is interrupted, and the error is returned. -func Walk(visit Visit, nodes ...SQLNode) error { - for _, node := range nodes { - if node == nil { - continue - } - kontinue, err := visit(node) - if err != nil { - return err - } - if kontinue { - err = node.walkSubtree(visit) - if err != nil { - return err - } - } - } - return nil -} - -// String returns a string representation of an SQLNode. -func String(node SQLNode) string { - if node == nil { - return "" - } - - buf := NewTrackedBuffer(nil) - buf.Myprintf("%v", node) - return buf.String() -} - -// Append appends the SQLNode to the buffer. -func Append(buf *bytes.Buffer, node SQLNode) { - tbuf := &TrackedBuffer{ - Buffer: buf, - } - node.Format(tbuf) -} - -// Statement represents a statement. -type Statement interface { - iStatement() - SQLNode -} - -func (*Union) iStatement() {} -func (*Select) iStatement() {} -func (*Stream) iStatement() {} -func (*Insert) iStatement() {} -func (*Update) iStatement() {} -func (*Delete) iStatement() {} -func (*Set) iStatement() {} -func (*DBDDL) iStatement() {} -func (*DDL) iStatement() {} -func (*Show) iStatement() {} -func (*Use) iStatement() {} -func (*Begin) iStatement() {} -func (*Commit) iStatement() {} -func (*Rollback) iStatement() {} -func (*OtherRead) iStatement() {} -func (*OtherAdmin) iStatement() {} - -// ParenSelect can actually not be a top level statement, -// but we have to allow it because it's a requirement -// of SelectStatement. -func (*ParenSelect) iStatement() {} - -// SelectStatement any SELECT statement. -type SelectStatement interface { - iSelectStatement() - iStatement() - iInsertRows() - AddOrder(*Order) - SetLimit(*Limit) - SQLNode -} - -func (*Select) iSelectStatement() {} -func (*Union) iSelectStatement() {} -func (*ParenSelect) iSelectStatement() {} - -// Select represents a SELECT statement. -type Select struct { - Cache string - Comments Comments - Distinct string - Hints string - SelectExprs SelectExprs - From TableExprs - Where *Where - GroupBy GroupBy - Having *Where - OrderBy OrderBy - Limit *Limit - Lock string -} - -// Select.Distinct -const ( - DistinctStr = "distinct " - StraightJoinHint = "straight_join " -) - -// Select.Lock -const ( - ForUpdateStr = " for update" - ShareModeStr = " lock in share mode" -) - -// Select.Cache -const ( - SQLCacheStr = "sql_cache " - SQLNoCacheStr = "sql_no_cache " -) - -// AddOrder adds an order by element -func (node *Select) AddOrder(order *Order) { - node.OrderBy = append(node.OrderBy, order) -} - -// SetLimit sets the limit clause -func (node *Select) SetLimit(limit *Limit) { - node.Limit = limit -} - -// Format formats the node. -func (node *Select) Format(buf *TrackedBuffer) { - buf.Myprintf("select %v%s%s%s%v from %v%v%v%v%v%v%s", - node.Comments, node.Cache, node.Distinct, node.Hints, node.SelectExprs, - node.From, node.Where, - node.GroupBy, node.Having, node.OrderBy, - node.Limit, node.Lock) -} - -func (node *Select) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.SelectExprs, - node.From, - node.Where, - node.GroupBy, - node.Having, - node.OrderBy, - node.Limit, - ) -} - -// AddWhere adds the boolean expression to the -// WHERE clause as an AND condition. If the expression -// is an OR clause, it parenthesizes it. Currently, -// the OR operator is the only one that's lower precedence -// than AND. -func (node *Select) AddWhere(expr Expr) { - if _, ok := expr.(*OrExpr); ok { - expr = &ParenExpr{Expr: expr} - } - if node.Where == nil { - node.Where = &Where{ - Type: WhereStr, - Expr: expr, - } - return - } - node.Where.Expr = &AndExpr{ - Left: node.Where.Expr, - Right: expr, - } - return -} - -// AddHaving adds the boolean expression to the -// HAVING clause as an AND condition. If the expression -// is an OR clause, it parenthesizes it. Currently, -// the OR operator is the only one that's lower precedence -// than AND. -func (node *Select) AddHaving(expr Expr) { - if _, ok := expr.(*OrExpr); ok { - expr = &ParenExpr{Expr: expr} - } - if node.Having == nil { - node.Having = &Where{ - Type: HavingStr, - Expr: expr, - } - return - } - node.Having.Expr = &AndExpr{ - Left: node.Having.Expr, - Right: expr, - } - return -} - -// ParenSelect is a parenthesized SELECT statement. -type ParenSelect struct { - Select SelectStatement -} - -// AddOrder adds an order by element -func (node *ParenSelect) AddOrder(order *Order) { - panic("unreachable") -} - -// SetLimit sets the limit clause -func (node *ParenSelect) SetLimit(limit *Limit) { - panic("unreachable") -} - -// Format formats the node. -func (node *ParenSelect) Format(buf *TrackedBuffer) { - buf.Myprintf("(%v)", node.Select) -} - -func (node *ParenSelect) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Select, - ) -} - -// Union represents a UNION statement. -type Union struct { - Type string - Left, Right SelectStatement - OrderBy OrderBy - Limit *Limit - Lock string -} - -// Union.Type -const ( - UnionStr = "union" - UnionAllStr = "union all" - UnionDistinctStr = "union distinct" -) - -// AddOrder adds an order by element -func (node *Union) AddOrder(order *Order) { - node.OrderBy = append(node.OrderBy, order) -} - -// SetLimit sets the limit clause -func (node *Union) SetLimit(limit *Limit) { - node.Limit = limit -} - -// Format formats the node. -func (node *Union) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s %v%v%v%s", node.Left, node.Type, node.Right, - node.OrderBy, node.Limit, node.Lock) -} - -func (node *Union) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.Right, - ) -} - -// Stream represents a SELECT statement. -type Stream struct { - Comments Comments - SelectExpr SelectExpr - Table TableName -} - -// Format formats the node. -func (node *Stream) Format(buf *TrackedBuffer) { - buf.Myprintf("stream %v%v from %v", - node.Comments, node.SelectExpr, node.Table) -} - -func (node *Stream) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.SelectExpr, - node.Table, - ) -} - -// Insert represents an INSERT or REPLACE statement. -// Per the MySQL docs, http://dev.mysql.com/doc/refman/5.7/en/replace.html -// Replace is the counterpart to `INSERT IGNORE`, and works exactly like a -// normal INSERT except if the row exists. In that case it first deletes -// the row and re-inserts with new values. For that reason we keep it as an Insert struct. -// Replaces are currently disallowed in sharded schemas because -// of the implications the deletion part may have on vindexes. -// If you add fields here, consider adding them to calls to validateSubquerySamePlan. -type Insert struct { - Action string - Comments Comments - Ignore string - Table TableName - Partitions Partitions - Columns Columns - Rows InsertRows - OnDup OnDup -} - -// DDL strings. -const ( - InsertStr = "insert" - ReplaceStr = "replace" -) - -// Format formats the node. -func (node *Insert) Format(buf *TrackedBuffer) { - buf.Myprintf("%s %v%sinto %v%v%v %v%v", - node.Action, - node.Comments, node.Ignore, - node.Table, node.Partitions, node.Columns, node.Rows, node.OnDup) -} - -func (node *Insert) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.Table, - node.Columns, - node.Rows, - node.OnDup, - ) -} - -// InsertRows represents the rows for an INSERT statement. -type InsertRows interface { - iInsertRows() - SQLNode -} - -func (*Select) iInsertRows() {} -func (*Union) iInsertRows() {} -func (Values) iInsertRows() {} -func (*ParenSelect) iInsertRows() {} - -// Update represents an UPDATE statement. -// If you add fields here, consider adding them to calls to validateSubquerySamePlan. -type Update struct { - Comments Comments - TableExprs TableExprs - Exprs UpdateExprs - Where *Where - OrderBy OrderBy - Limit *Limit -} - -// Format formats the node. -func (node *Update) Format(buf *TrackedBuffer) { - buf.Myprintf("update %v%v set %v%v%v%v", - node.Comments, node.TableExprs, - node.Exprs, node.Where, node.OrderBy, node.Limit) -} - -func (node *Update) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.TableExprs, - node.Exprs, - node.Where, - node.OrderBy, - node.Limit, - ) -} - -// Delete represents a DELETE statement. -// If you add fields here, consider adding them to calls to validateSubquerySamePlan. -type Delete struct { - Comments Comments - Targets TableNames - TableExprs TableExprs - Partitions Partitions - Where *Where - OrderBy OrderBy - Limit *Limit -} - -// Format formats the node. -func (node *Delete) Format(buf *TrackedBuffer) { - buf.Myprintf("delete %v", node.Comments) - if node.Targets != nil { - buf.Myprintf("%v ", node.Targets) - } - buf.Myprintf("from %v%v%v%v%v", node.TableExprs, node.Partitions, node.Where, node.OrderBy, node.Limit) -} - -func (node *Delete) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.Targets, - node.TableExprs, - node.Where, - node.OrderBy, - node.Limit, - ) -} - -// Set represents a SET statement. -type Set struct { - Comments Comments - Exprs SetExprs - Scope string -} - -// Set.Scope or Show.Scope -const ( - SessionStr = "session" - GlobalStr = "global" -) - -// Format formats the node. -func (node *Set) Format(buf *TrackedBuffer) { - if node.Scope == "" { - buf.Myprintf("set %v%v", node.Comments, node.Exprs) - } else { - buf.Myprintf("set %v%s %v", node.Comments, node.Scope, node.Exprs) - } -} - -func (node *Set) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Comments, - node.Exprs, - ) -} - -// DBDDL represents a CREATE, DROP database statement. -type DBDDL struct { - Action string - DBName string - IfExists bool - Collate string - Charset string -} - -// Format formats the node. -func (node *DBDDL) Format(buf *TrackedBuffer) { - switch node.Action { - case CreateStr: - buf.WriteString(fmt.Sprintf("%s database %s", node.Action, node.DBName)) - case DropStr: - exists := "" - if node.IfExists { - exists = " if exists" - } - buf.WriteString(fmt.Sprintf("%s database%s %v", node.Action, exists, node.DBName)) - } -} - -// walkSubtree walks the nodes of the subtree. -func (node *DBDDL) walkSubtree(visit Visit) error { - return nil -} - -// DDL represents a CREATE, ALTER, DROP, RENAME or TRUNCATE statement. -// Table is set for AlterStr, DropStr, RenameStr, TruncateStr -// NewName is set for AlterStr, CreateStr, RenameStr. -// VindexSpec is set for CreateVindexStr, DropVindexStr, AddColVindexStr, DropColVindexStr -// VindexCols is set for AddColVindexStr -type DDL struct { - Action string - Table TableName - NewName TableName - IfExists bool - TableSpec *TableSpec - PartitionSpec *PartitionSpec - VindexSpec *VindexSpec - VindexCols []ColIdent -} - -// DDL strings. -const ( - CreateStr = "create" - AlterStr = "alter" - DropStr = "drop" - RenameStr = "rename" - TruncateStr = "truncate" - CreateVindexStr = "create vindex" - AddColVindexStr = "add vindex" - DropColVindexStr = "drop vindex" - - // Vindex DDL param to specify the owner of a vindex - VindexOwnerStr = "owner" -) - -// Format formats the node. -func (node *DDL) Format(buf *TrackedBuffer) { - switch node.Action { - case CreateStr: - if node.TableSpec == nil { - buf.Myprintf("%s table %v", node.Action, node.NewName) - } else { - buf.Myprintf("%s table %v %v", node.Action, node.NewName, node.TableSpec) - } - case DropStr: - exists := "" - if node.IfExists { - exists = " if exists" - } - buf.Myprintf("%s table%s %v", node.Action, exists, node.Table) - case RenameStr: - buf.Myprintf("%s table %v to %v", node.Action, node.Table, node.NewName) - case AlterStr: - if node.PartitionSpec != nil { - buf.Myprintf("%s table %v %v", node.Action, node.Table, node.PartitionSpec) - } else { - buf.Myprintf("%s table %v", node.Action, node.Table) - } - case CreateVindexStr: - buf.Myprintf("%s %v %v", node.Action, node.VindexSpec.Name, node.VindexSpec) - case AddColVindexStr: - buf.Myprintf("alter table %v %s %v (", node.Table, node.Action, node.VindexSpec.Name) - for i, col := range node.VindexCols { - if i != 0 { - buf.Myprintf(", %v", col) - } else { - buf.Myprintf("%v", col) - } - } - buf.Myprintf(")") - if node.VindexSpec.Type.String() != "" { - buf.Myprintf(" %v", node.VindexSpec) - } - case DropColVindexStr: - buf.Myprintf("alter table %v %s %v", node.Table, node.Action, node.VindexSpec.Name) - default: - buf.Myprintf("%s table %v", node.Action, node.Table) - } -} - -func (node *DDL) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Table, - node.NewName, - ) -} - -// Partition strings -const ( - ReorganizeStr = "reorganize partition" -) - -// PartitionSpec describe partition actions (for alter and create) -type PartitionSpec struct { - Action string - Name ColIdent - Definitions []*PartitionDefinition -} - -// Format formats the node. -func (node *PartitionSpec) Format(buf *TrackedBuffer) { - switch node.Action { - case ReorganizeStr: - buf.Myprintf("%s %v into (", node.Action, node.Name) - var prefix string - for _, pd := range node.Definitions { - buf.Myprintf("%s%v", prefix, pd) - prefix = ", " - } - buf.Myprintf(")") - default: - panic("unimplemented") - } -} - -func (node *PartitionSpec) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - if err := Walk(visit, node.Name); err != nil { - return err - } - for _, def := range node.Definitions { - if err := Walk(visit, def); err != nil { - return err - } - } - return nil -} - -// PartitionDefinition describes a very minimal partition definition -type PartitionDefinition struct { - Name ColIdent - Limit Expr - Maxvalue bool -} - -// Format formats the node -func (node *PartitionDefinition) Format(buf *TrackedBuffer) { - if !node.Maxvalue { - buf.Myprintf("partition %v values less than (%v)", node.Name, node.Limit) - } else { - buf.Myprintf("partition %v values less than (maxvalue)", node.Name) - } -} - -func (node *PartitionDefinition) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - node.Limit, - ) -} - -// TableSpec describes the structure of a table from a CREATE TABLE statement -type TableSpec struct { - Columns []*ColumnDefinition - Indexes []*IndexDefinition - Options string -} - -// Format formats the node. -func (ts *TableSpec) Format(buf *TrackedBuffer) { - buf.Myprintf("(\n") - for i, col := range ts.Columns { - if i == 0 { - buf.Myprintf("\t%v", col) - } else { - buf.Myprintf(",\n\t%v", col) - } - } - for _, idx := range ts.Indexes { - buf.Myprintf(",\n\t%v", idx) - } - - buf.Myprintf("\n)%s", strings.Replace(ts.Options, ", ", ",\n ", -1)) -} - -// AddColumn appends the given column to the list in the spec -func (ts *TableSpec) AddColumn(cd *ColumnDefinition) { - ts.Columns = append(ts.Columns, cd) -} - -// AddIndex appends the given index to the list in the spec -func (ts *TableSpec) AddIndex(id *IndexDefinition) { - ts.Indexes = append(ts.Indexes, id) -} - -func (ts *TableSpec) walkSubtree(visit Visit) error { - if ts == nil { - return nil - } - - for _, n := range ts.Columns { - if err := Walk(visit, n); err != nil { - return err - } - } - - for _, n := range ts.Indexes { - if err := Walk(visit, n); err != nil { - return err - } - } - - return nil -} - -// ColumnDefinition describes a column in a CREATE TABLE statement -type ColumnDefinition struct { - Name ColIdent - Type ColumnType -} - -// Format formats the node. -func (col *ColumnDefinition) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %v", col.Name, &col.Type) -} - -func (col *ColumnDefinition) walkSubtree(visit Visit) error { - if col == nil { - return nil - } - return Walk( - visit, - col.Name, - &col.Type, - ) -} - -// ColumnType represents a sql type in a CREATE TABLE statement -// All optional fields are nil if not specified -type ColumnType struct { - // The base type string - Type string - - // Generic field options. - NotNull BoolVal - Autoincrement BoolVal - Default *SQLVal - OnUpdate *SQLVal - Comment *SQLVal - - // Numeric field options - Length *SQLVal - Unsigned BoolVal - Zerofill BoolVal - Scale *SQLVal - - // Text field options - Charset string - Collate string - - // Enum values - EnumValues []string - - // Key specification - KeyOpt ColumnKeyOption -} - -// Format returns a canonical string representation of the type and all relevant options -func (ct *ColumnType) Format(buf *TrackedBuffer) { - buf.Myprintf("%s", ct.Type) - - if ct.Length != nil && ct.Scale != nil { - buf.Myprintf("(%v,%v)", ct.Length, ct.Scale) - - } else if ct.Length != nil { - buf.Myprintf("(%v)", ct.Length) - } - - if ct.EnumValues != nil { - buf.Myprintf("(%s)", strings.Join(ct.EnumValues, ", ")) - } - - opts := make([]string, 0, 16) - if ct.Unsigned { - opts = append(opts, keywordStrings[UNSIGNED]) - } - if ct.Zerofill { - opts = append(opts, keywordStrings[ZEROFILL]) - } - if ct.Charset != "" { - opts = append(opts, keywordStrings[CHARACTER], keywordStrings[SET], ct.Charset) - } - if ct.Collate != "" { - opts = append(opts, keywordStrings[COLLATE], ct.Collate) - } - if ct.NotNull { - opts = append(opts, keywordStrings[NOT], keywordStrings[NULL]) - } - if ct.Default != nil { - opts = append(opts, keywordStrings[DEFAULT], String(ct.Default)) - } - if ct.OnUpdate != nil { - opts = append(opts, keywordStrings[ON], keywordStrings[UPDATE], String(ct.OnUpdate)) - } - if ct.Autoincrement { - opts = append(opts, keywordStrings[AUTO_INCREMENT]) - } - if ct.Comment != nil { - opts = append(opts, keywordStrings[COMMENT_KEYWORD], String(ct.Comment)) - } - if ct.KeyOpt == colKeyPrimary { - opts = append(opts, keywordStrings[PRIMARY], keywordStrings[KEY]) - } - if ct.KeyOpt == colKeyUnique { - opts = append(opts, keywordStrings[UNIQUE]) - } - if ct.KeyOpt == colKeyUniqueKey { - opts = append(opts, keywordStrings[UNIQUE], keywordStrings[KEY]) - } - if ct.KeyOpt == colKeySpatialKey { - opts = append(opts, keywordStrings[SPATIAL], keywordStrings[KEY]) - } - if ct.KeyOpt == colKey { - opts = append(opts, keywordStrings[KEY]) - } - - if len(opts) != 0 { - buf.Myprintf(" %s", strings.Join(opts, " ")) - } -} - -// DescribeType returns the abbreviated type information as required for -// describe table -func (ct *ColumnType) DescribeType() string { - buf := NewTrackedBuffer(nil) - buf.Myprintf("%s", ct.Type) - if ct.Length != nil && ct.Scale != nil { - buf.Myprintf("(%v,%v)", ct.Length, ct.Scale) - } else if ct.Length != nil { - buf.Myprintf("(%v)", ct.Length) - } - - opts := make([]string, 0, 16) - if ct.Unsigned { - opts = append(opts, keywordStrings[UNSIGNED]) - } - if ct.Zerofill { - opts = append(opts, keywordStrings[ZEROFILL]) - } - if len(opts) != 0 { - buf.Myprintf(" %s", strings.Join(opts, " ")) - } - return buf.String() -} - -// SQLType returns the sqltypes type code for the given column -func (ct *ColumnType) SQLType() querypb.Type { - switch ct.Type { - case keywordStrings[TINYINT]: - if ct.Unsigned { - return sqltypes.Uint8 - } - return sqltypes.Int8 - case keywordStrings[SMALLINT]: - if ct.Unsigned { - return sqltypes.Uint16 - } - return sqltypes.Int16 - case keywordStrings[MEDIUMINT]: - if ct.Unsigned { - return sqltypes.Uint24 - } - return sqltypes.Int24 - case keywordStrings[INT]: - fallthrough - case keywordStrings[INTEGER]: - if ct.Unsigned { - return sqltypes.Uint32 - } - return sqltypes.Int32 - case keywordStrings[BIGINT]: - if ct.Unsigned { - return sqltypes.Uint64 - } - return sqltypes.Int64 - case keywordStrings[TEXT]: - return sqltypes.Text - case keywordStrings[TINYTEXT]: - return sqltypes.Text - case keywordStrings[MEDIUMTEXT]: - return sqltypes.Text - case keywordStrings[LONGTEXT]: - return sqltypes.Text - case keywordStrings[BLOB]: - return sqltypes.Blob - case keywordStrings[TINYBLOB]: - return sqltypes.Blob - case keywordStrings[MEDIUMBLOB]: - return sqltypes.Blob - case keywordStrings[LONGBLOB]: - return sqltypes.Blob - case keywordStrings[CHAR]: - return sqltypes.Char - case keywordStrings[VARCHAR]: - return sqltypes.VarChar - case keywordStrings[BINARY]: - return sqltypes.Binary - case keywordStrings[VARBINARY]: - return sqltypes.VarBinary - case keywordStrings[DATE]: - return sqltypes.Date - case keywordStrings[TIME]: - return sqltypes.Time - case keywordStrings[DATETIME]: - return sqltypes.Datetime - case keywordStrings[TIMESTAMP]: - return sqltypes.Timestamp - case keywordStrings[YEAR]: - return sqltypes.Year - case keywordStrings[FLOAT_TYPE]: - return sqltypes.Float32 - case keywordStrings[DOUBLE]: - return sqltypes.Float64 - case keywordStrings[DECIMAL]: - return sqltypes.Decimal - case keywordStrings[BIT]: - return sqltypes.Bit - case keywordStrings[ENUM]: - return sqltypes.Enum - case keywordStrings[SET]: - return sqltypes.Set - case keywordStrings[JSON]: - return sqltypes.TypeJSON - case keywordStrings[GEOMETRY]: - return sqltypes.Geometry - case keywordStrings[POINT]: - return sqltypes.Geometry - case keywordStrings[LINESTRING]: - return sqltypes.Geometry - case keywordStrings[POLYGON]: - return sqltypes.Geometry - case keywordStrings[GEOMETRYCOLLECTION]: - return sqltypes.Geometry - case keywordStrings[MULTIPOINT]: - return sqltypes.Geometry - case keywordStrings[MULTILINESTRING]: - return sqltypes.Geometry - case keywordStrings[MULTIPOLYGON]: - return sqltypes.Geometry - } - panic("unimplemented type " + ct.Type) -} - -func (ct *ColumnType) walkSubtree(visit Visit) error { - return nil -} - -// IndexDefinition describes an index in a CREATE TABLE statement -type IndexDefinition struct { - Info *IndexInfo - Columns []*IndexColumn - Options []*IndexOption -} - -// Format formats the node. -func (idx *IndexDefinition) Format(buf *TrackedBuffer) { - buf.Myprintf("%v (", idx.Info) - for i, col := range idx.Columns { - if i != 0 { - buf.Myprintf(", %v", col.Column) - } else { - buf.Myprintf("%v", col.Column) - } - if col.Length != nil { - buf.Myprintf("(%v)", col.Length) - } - } - buf.Myprintf(")") - - for _, opt := range idx.Options { - buf.Myprintf(" %s", opt.Name) - if opt.Using != "" { - buf.Myprintf(" %s", opt.Using) - } else { - buf.Myprintf(" %v", opt.Value) - } - } -} - -func (idx *IndexDefinition) walkSubtree(visit Visit) error { - if idx == nil { - return nil - } - - for _, n := range idx.Columns { - if err := Walk(visit, n.Column); err != nil { - return err - } - } - - return nil -} - -// IndexInfo describes the name and type of an index in a CREATE TABLE statement -type IndexInfo struct { - Type string - Name ColIdent - Primary bool - Spatial bool - Unique bool -} - -// Format formats the node. -func (ii *IndexInfo) Format(buf *TrackedBuffer) { - if ii.Primary { - buf.Myprintf("%s", ii.Type) - } else { - buf.Myprintf("%s %v", ii.Type, ii.Name) - } -} - -func (ii *IndexInfo) walkSubtree(visit Visit) error { - return Walk(visit, ii.Name) -} - -// IndexColumn describes a column in an index definition with optional length -type IndexColumn struct { - Column ColIdent - Length *SQLVal -} - -// LengthScaleOption is used for types that have an optional length -// and scale -type LengthScaleOption struct { - Length *SQLVal - Scale *SQLVal -} - -// IndexOption is used for trailing options for indexes: COMMENT, KEY_BLOCK_SIZE, USING -type IndexOption struct { - Name string - Value *SQLVal - Using string -} - -// ColumnKeyOption indicates whether or not the given column is defined as an -// index element and contains the type of the option -type ColumnKeyOption int - -const ( - colKeyNone ColumnKeyOption = iota - colKeyPrimary - colKeySpatialKey - colKeyUnique - colKeyUniqueKey - colKey -) - -// VindexSpec defines a vindex for a CREATE VINDEX or DROP VINDEX statement -type VindexSpec struct { - Name ColIdent - Type ColIdent - Params []VindexParam -} - -// ParseParams parses the vindex parameter list, pulling out the special-case -// "owner" parameter -func (node *VindexSpec) ParseParams() (string, map[string]string) { - var owner string - params := map[string]string{} - for _, p := range node.Params { - if p.Key.Lowered() == VindexOwnerStr { - owner = p.Val - } else { - params[p.Key.String()] = p.Val - } - } - return owner, params -} - -// Format formats the node. The "CREATE VINDEX" preamble was formatted in -// the containing DDL node Format, so this just prints the type, any -// parameters, and optionally the owner -func (node *VindexSpec) Format(buf *TrackedBuffer) { - buf.Myprintf("using %v", node.Type) - - numParams := len(node.Params) - if numParams != 0 { - buf.Myprintf(" with ") - for i, p := range node.Params { - if i != 0 { - buf.Myprintf(", ") - } - buf.Myprintf("%v", p) - } - } -} - -func (node *VindexSpec) walkSubtree(visit Visit) error { - err := Walk(visit, - node.Name, - ) - - if err != nil { - return err - } - - for _, p := range node.Params { - err := Walk(visit, p) - - if err != nil { - return err - } - } - return nil -} - -// VindexParam defines a key/value parameter for a CREATE VINDEX statement -type VindexParam struct { - Key ColIdent - Val string -} - -// Format formats the node. -func (node VindexParam) Format(buf *TrackedBuffer) { - buf.Myprintf("%s=%s", node.Key.String(), node.Val) -} - -func (node VindexParam) walkSubtree(visit Visit) error { - return Walk(visit, - node.Key, - ) -} - -// Show represents a show statement. -type Show struct { - Type string - OnTable TableName - ShowTablesOpt *ShowTablesOpt - Scope string -} - -// Format formats the node. -func (node *Show) Format(buf *TrackedBuffer) { - if node.Type == "tables" && node.ShowTablesOpt != nil { - opt := node.ShowTablesOpt - if opt.DbName != "" { - if opt.Filter != nil { - buf.Myprintf("show %s%stables from %s %v", opt.Extended, opt.Full, opt.DbName, opt.Filter) - } else { - buf.Myprintf("show %s%stables from %s", opt.Extended, opt.Full, opt.DbName) - } - } else { - if opt.Filter != nil { - buf.Myprintf("show %s%stables %v", opt.Extended, opt.Full, opt.Filter) - } else { - buf.Myprintf("show %s%stables", opt.Extended, opt.Full) - } - } - return - } - if node.Scope == "" { - buf.Myprintf("show %s", node.Type) - } else { - buf.Myprintf("show %s %s", node.Scope, node.Type) - } - if node.HasOnTable() { - buf.Myprintf(" on %v", node.OnTable) - } -} - -// HasOnTable returns true if the show statement has an "on" clause -func (node *Show) HasOnTable() bool { - return node.OnTable.Name.v != "" -} - -func (node *Show) walkSubtree(visit Visit) error { - return nil -} - -// ShowTablesOpt is show tables option -type ShowTablesOpt struct { - Extended string - Full string - DbName string - Filter *ShowFilter -} - -// ShowFilter is show tables filter -type ShowFilter struct { - Like string - Filter Expr -} - -// Format formats the node. -func (node *ShowFilter) Format(buf *TrackedBuffer) { - if node.Like != "" { - buf.Myprintf("like '%s'", node.Like) - } else { - buf.Myprintf("where %v", node.Filter) - } -} - -func (node *ShowFilter) walkSubtree(visit Visit) error { - return nil -} - -// Use represents a use statement. -type Use struct { - DBName TableIdent -} - -// Format formats the node. -func (node *Use) Format(buf *TrackedBuffer) { - if node.DBName.v != "" { - buf.Myprintf("use %v", node.DBName) - } else { - buf.Myprintf("use") - } -} - -func (node *Use) walkSubtree(visit Visit) error { - return Walk(visit, node.DBName) -} - -// Begin represents a Begin statement. -type Begin struct{} - -// Format formats the node. -func (node *Begin) Format(buf *TrackedBuffer) { - buf.WriteString("begin") -} - -func (node *Begin) walkSubtree(visit Visit) error { - return nil -} - -// Commit represents a Commit statement. -type Commit struct{} - -// Format formats the node. -func (node *Commit) Format(buf *TrackedBuffer) { - buf.WriteString("commit") -} - -func (node *Commit) walkSubtree(visit Visit) error { - return nil -} - -// Rollback represents a Rollback statement. -type Rollback struct{} - -// Format formats the node. -func (node *Rollback) Format(buf *TrackedBuffer) { - buf.WriteString("rollback") -} - -func (node *Rollback) walkSubtree(visit Visit) error { - return nil -} - -// OtherRead represents a DESCRIBE, or EXPLAIN statement. -// It should be used only as an indicator. It does not contain -// the full AST for the statement. -type OtherRead struct{} - -// Format formats the node. -func (node *OtherRead) Format(buf *TrackedBuffer) { - buf.WriteString("otherread") -} - -func (node *OtherRead) walkSubtree(visit Visit) error { - return nil -} - -// OtherAdmin represents a misc statement that relies on ADMIN privileges, -// such as REPAIR, OPTIMIZE, or TRUNCATE statement. -// It should be used only as an indicator. It does not contain -// the full AST for the statement. -type OtherAdmin struct{} - -// Format formats the node. -func (node *OtherAdmin) Format(buf *TrackedBuffer) { - buf.WriteString("otheradmin") -} - -func (node *OtherAdmin) walkSubtree(visit Visit) error { - return nil -} - -// Comments represents a list of comments. -type Comments [][]byte - -// Format formats the node. -func (node Comments) Format(buf *TrackedBuffer) { - for _, c := range node { - buf.Myprintf("%s ", c) - } -} - -func (node Comments) walkSubtree(visit Visit) error { - return nil -} - -// SelectExprs represents SELECT expressions. -type SelectExprs []SelectExpr - -// Format formats the node. -func (node SelectExprs) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node SelectExprs) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// SelectExpr represents a SELECT expression. -type SelectExpr interface { - iSelectExpr() - SQLNode -} - -func (*StarExpr) iSelectExpr() {} -func (*AliasedExpr) iSelectExpr() {} -func (Nextval) iSelectExpr() {} - -// StarExpr defines a '*' or 'table.*' expression. -type StarExpr struct { - TableName TableName -} - -// Format formats the node. -func (node *StarExpr) Format(buf *TrackedBuffer) { - if !node.TableName.IsEmpty() { - buf.Myprintf("%v.", node.TableName) - } - buf.Myprintf("*") -} - -func (node *StarExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.TableName, - ) -} - -// AliasedExpr defines an aliased SELECT expression. -type AliasedExpr struct { - Expr Expr - As ColIdent -} - -// Format formats the node. -func (node *AliasedExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v", node.Expr) - if !node.As.IsEmpty() { - buf.Myprintf(" as %v", node.As) - } -} - -func (node *AliasedExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - node.As, - ) -} - -// Nextval defines the NEXT VALUE expression. -type Nextval struct { - Expr Expr -} - -// Format formats the node. -func (node Nextval) Format(buf *TrackedBuffer) { - buf.Myprintf("next %v values", node.Expr) -} - -func (node Nextval) walkSubtree(visit Visit) error { - return Walk(visit, node.Expr) -} - -// Columns represents an insert column list. -type Columns []ColIdent - -// Format formats the node. -func (node Columns) Format(buf *TrackedBuffer) { - if node == nil { - return - } - prefix := "(" - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } - buf.WriteString(")") -} - -func (node Columns) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// FindColumn finds a column in the column list, returning -// the index if it exists or -1 otherwise -func (node Columns) FindColumn(col ColIdent) int { - for i, colName := range node { - if colName.Equal(col) { - return i - } - } - return -1 -} - -// Partitions is a type alias for Columns so we can handle printing efficiently -type Partitions Columns - -// Format formats the node -func (node Partitions) Format(buf *TrackedBuffer) { - if node == nil { - return - } - prefix := " partition (" - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } - buf.WriteString(")") -} - -func (node Partitions) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// TableExprs represents a list of table expressions. -type TableExprs []TableExpr - -// Format formats the node. -func (node TableExprs) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node TableExprs) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// TableExpr represents a table expression. -type TableExpr interface { - iTableExpr() - SQLNode -} - -func (*AliasedTableExpr) iTableExpr() {} -func (*ParenTableExpr) iTableExpr() {} -func (*JoinTableExpr) iTableExpr() {} - -// AliasedTableExpr represents a table expression -// coupled with an optional alias or index hint. -// If As is empty, no alias was used. -type AliasedTableExpr struct { - Expr SimpleTableExpr - Partitions Partitions - As TableIdent - Hints *IndexHints -} - -// Format formats the node. -func (node *AliasedTableExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v%v", node.Expr, node.Partitions) - if !node.As.IsEmpty() { - buf.Myprintf(" as %v", node.As) - } - if node.Hints != nil { - // Hint node provides the space padding. - buf.Myprintf("%v", node.Hints) - } -} - -func (node *AliasedTableExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - node.As, - node.Hints, - ) -} - -// RemoveHints returns a new AliasedTableExpr with the hints removed. -func (node *AliasedTableExpr) RemoveHints() *AliasedTableExpr { - noHints := *node - noHints.Hints = nil - return &noHints -} - -// SimpleTableExpr represents a simple table expression. -type SimpleTableExpr interface { - iSimpleTableExpr() - SQLNode -} - -func (TableName) iSimpleTableExpr() {} -func (*Subquery) iSimpleTableExpr() {} - -// TableNames is a list of TableName. -type TableNames []TableName - -// Format formats the node. -func (node TableNames) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node TableNames) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// TableName represents a table name. -// Qualifier, if specified, represents a database or keyspace. -// TableName is a value struct whose fields are case sensitive. -// This means two TableName vars can be compared for equality -// and a TableName can also be used as key in a map. -type TableName struct { - Name, Qualifier TableIdent -} - -// Format formats the node. -func (node TableName) Format(buf *TrackedBuffer) { - if node.IsEmpty() { - return - } - if !node.Qualifier.IsEmpty() { - buf.Myprintf("%v.", node.Qualifier) - } - buf.Myprintf("%v", node.Name) -} - -func (node TableName) walkSubtree(visit Visit) error { - return Walk( - visit, - node.Name, - node.Qualifier, - ) -} - -// IsEmpty returns true if TableName is nil or empty. -func (node TableName) IsEmpty() bool { - // If Name is empty, Qualifer is also empty. - return node.Name.IsEmpty() -} - -// ToViewName returns a TableName acceptable for use as a VIEW. VIEW names are -// always lowercase, so ToViewName lowercasese the name. Databases are case-sensitive -// so Qualifier is left untouched. -func (node TableName) ToViewName() TableName { - return TableName{ - Qualifier: node.Qualifier, - Name: NewTableIdent(strings.ToLower(node.Name.v)), - } -} - -// ParenTableExpr represents a parenthesized list of TableExpr. -type ParenTableExpr struct { - Exprs TableExprs -} - -// Format formats the node. -func (node *ParenTableExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("(%v)", node.Exprs) -} - -func (node *ParenTableExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Exprs, - ) -} - -// JoinCondition represents the join conditions (either a ON or USING clause) -// of a JoinTableExpr. -type JoinCondition struct { - On Expr - Using Columns -} - -// Format formats the node. -func (node JoinCondition) Format(buf *TrackedBuffer) { - if node.On != nil { - buf.Myprintf(" on %v", node.On) - } - if node.Using != nil { - buf.Myprintf(" using %v", node.Using) - } -} - -func (node JoinCondition) walkSubtree(visit Visit) error { - return Walk( - visit, - node.On, - node.Using, - ) -} - -// JoinTableExpr represents a TableExpr that's a JOIN operation. -type JoinTableExpr struct { - LeftExpr TableExpr - Join string - RightExpr TableExpr - Condition JoinCondition -} - -// JoinTableExpr.Join -const ( - JoinStr = "join" - StraightJoinStr = "straight_join" - LeftJoinStr = "left join" - RightJoinStr = "right join" - NaturalJoinStr = "natural join" - NaturalLeftJoinStr = "natural left join" - NaturalRightJoinStr = "natural right join" -) - -// Format formats the node. -func (node *JoinTableExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s %v%v", node.LeftExpr, node.Join, node.RightExpr, node.Condition) -} - -func (node *JoinTableExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.LeftExpr, - node.RightExpr, - node.Condition, - ) -} - -// IndexHints represents a list of index hints. -type IndexHints struct { - Type string - Indexes []ColIdent -} - -// Index hints. -const ( - UseStr = "use " - IgnoreStr = "ignore " - ForceStr = "force " -) - -// Format formats the node. -func (node *IndexHints) Format(buf *TrackedBuffer) { - buf.Myprintf(" %sindex ", node.Type) - prefix := "(" - for _, n := range node.Indexes { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } - buf.Myprintf(")") -} - -func (node *IndexHints) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - for _, n := range node.Indexes { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// Where represents a WHERE or HAVING clause. -type Where struct { - Type string - Expr Expr -} - -// Where.Type -const ( - WhereStr = "where" - HavingStr = "having" -) - -// NewWhere creates a WHERE or HAVING clause out -// of a Expr. If the expression is nil, it returns nil. -func NewWhere(typ string, expr Expr) *Where { - if expr == nil { - return nil - } - return &Where{Type: typ, Expr: expr} -} - -// Format formats the node. -func (node *Where) Format(buf *TrackedBuffer) { - if node == nil || node.Expr == nil { - return - } - buf.Myprintf(" %s %v", node.Type, node.Expr) -} - -func (node *Where) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -// Expr represents an expression. -type Expr interface { - iExpr() - // replace replaces any subexpression that matches - // from with to. The implementation can use the - // replaceExprs convenience function. - replace(from, to Expr) bool - SQLNode -} - -func (*AndExpr) iExpr() {} -func (*OrExpr) iExpr() {} -func (*NotExpr) iExpr() {} -func (*ParenExpr) iExpr() {} -func (*ComparisonExpr) iExpr() {} -func (*RangeCond) iExpr() {} -func (*IsExpr) iExpr() {} -func (*ExistsExpr) iExpr() {} -func (*SQLVal) iExpr() {} -func (*NullVal) iExpr() {} -func (BoolVal) iExpr() {} -func (*ColName) iExpr() {} -func (ValTuple) iExpr() {} -func (*Subquery) iExpr() {} -func (ListArg) iExpr() {} -func (*BinaryExpr) iExpr() {} -func (*UnaryExpr) iExpr() {} -func (*IntervalExpr) iExpr() {} -func (*CollateExpr) iExpr() {} -func (*FuncExpr) iExpr() {} -func (*CaseExpr) iExpr() {} -func (*ValuesFuncExpr) iExpr() {} -func (*ConvertExpr) iExpr() {} -func (*SubstrExpr) iExpr() {} -func (*ConvertUsingExpr) iExpr() {} -func (*MatchExpr) iExpr() {} -func (*GroupConcatExpr) iExpr() {} -func (*Default) iExpr() {} - -// ReplaceExpr finds the from expression from root -// and replaces it with to. If from matches root, -// then to is returned. -func ReplaceExpr(root, from, to Expr) Expr { - if root == from { - return to - } - root.replace(from, to) - return root -} - -// replaceExprs is a convenience function used by implementors -// of the replace method. -func replaceExprs(from, to Expr, exprs ...*Expr) bool { - for _, expr := range exprs { - if *expr == nil { - continue - } - if *expr == from { - *expr = to - return true - } - if (*expr).replace(from, to) { - return true - } - } - return false -} - -// Exprs represents a list of value expressions. -// It's not a valid expression because it's not parenthesized. -type Exprs []Expr - -// Format formats the node. -func (node Exprs) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node Exprs) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// AndExpr represents an AND expression. -type AndExpr struct { - Left, Right Expr -} - -// Format formats the node. -func (node *AndExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v and %v", node.Left, node.Right) -} - -func (node *AndExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.Right, - ) -} - -func (node *AndExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Left, &node.Right) -} - -// OrExpr represents an OR expression. -type OrExpr struct { - Left, Right Expr -} - -// Format formats the node. -func (node *OrExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v or %v", node.Left, node.Right) -} - -func (node *OrExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.Right, - ) -} - -func (node *OrExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Left, &node.Right) -} - -// NotExpr represents a NOT expression. -type NotExpr struct { - Expr Expr -} - -// Format formats the node. -func (node *NotExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("not %v", node.Expr) -} - -func (node *NotExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *NotExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// ParenExpr represents a parenthesized boolean expression. -type ParenExpr struct { - Expr Expr -} - -// Format formats the node. -func (node *ParenExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("(%v)", node.Expr) -} - -func (node *ParenExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *ParenExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// ComparisonExpr represents a two-value comparison expression. -type ComparisonExpr struct { - Operator string - Left, Right Expr - Escape Expr -} - -// ComparisonExpr.Operator -const ( - EqualStr = "=" - LessThanStr = "<" - GreaterThanStr = ">" - LessEqualStr = "<=" - GreaterEqualStr = ">=" - NotEqualStr = "!=" - NullSafeEqualStr = "<=>" - InStr = "in" - NotInStr = "not in" - LikeStr = "like" - NotLikeStr = "not like" - RegexpStr = "regexp" - NotRegexpStr = "not regexp" - JSONExtractOp = "->" - JSONUnquoteExtractOp = "->>" -) - -// Format formats the node. -func (node *ComparisonExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s %v", node.Left, node.Operator, node.Right) - if node.Escape != nil { - buf.Myprintf(" escape %v", node.Escape) - } -} - -func (node *ComparisonExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.Right, - node.Escape, - ) -} - -func (node *ComparisonExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Left, &node.Right, &node.Escape) -} - -// RangeCond represents a BETWEEN or a NOT BETWEEN expression. -type RangeCond struct { - Operator string - Left Expr - From, To Expr -} - -// RangeCond.Operator -const ( - BetweenStr = "between" - NotBetweenStr = "not between" -) - -// Format formats the node. -func (node *RangeCond) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s %v and %v", node.Left, node.Operator, node.From, node.To) -} - -func (node *RangeCond) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.From, - node.To, - ) -} - -func (node *RangeCond) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Left, &node.From, &node.To) -} - -// IsExpr represents an IS ... or an IS NOT ... expression. -type IsExpr struct { - Operator string - Expr Expr -} - -// IsExpr.Operator -const ( - IsNullStr = "is null" - IsNotNullStr = "is not null" - IsTrueStr = "is true" - IsNotTrueStr = "is not true" - IsFalseStr = "is false" - IsNotFalseStr = "is not false" -) - -// Format formats the node. -func (node *IsExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s", node.Expr, node.Operator) -} - -func (node *IsExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *IsExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// ExistsExpr represents an EXISTS expression. -type ExistsExpr struct { - Subquery *Subquery -} - -// Format formats the node. -func (node *ExistsExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("exists %v", node.Subquery) -} - -func (node *ExistsExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Subquery, - ) -} - -func (node *ExistsExpr) replace(from, to Expr) bool { - return false -} - -// ExprFromValue converts the given Value into an Expr or returns an error. -func ExprFromValue(value sqltypes.Value) (Expr, error) { - // The type checks here follow the rules defined in sqltypes/types.go. - switch { - case value.Type() == sqltypes.Null: - return &NullVal{}, nil - case value.IsIntegral(): - return NewIntVal(value.ToBytes()), nil - case value.IsFloat() || value.Type() == sqltypes.Decimal: - return NewFloatVal(value.ToBytes()), nil - case value.IsQuoted(): - return NewStrVal(value.ToBytes()), nil - default: - // We cannot support sqltypes.Expression, or any other invalid type. - return nil, fmt.Errorf("cannot convert value %v to AST", value) - } -} - -// ValType specifies the type for SQLVal. -type ValType int - -// These are the possible Valtype values. -// HexNum represents a 0x... value. It cannot -// be treated as a simple value because it can -// be interpreted differently depending on the -// context. -const ( - StrVal = ValType(iota) - IntVal - FloatVal - HexNum - HexVal - ValArg - BitVal -) - -// SQLVal represents a single value. -type SQLVal struct { - Type ValType - Val []byte -} - -// NewStrVal builds a new StrVal. -func NewStrVal(in []byte) *SQLVal { - return &SQLVal{Type: StrVal, Val: in} -} - -// NewIntVal builds a new IntVal. -func NewIntVal(in []byte) *SQLVal { - return &SQLVal{Type: IntVal, Val: in} -} - -// NewFloatVal builds a new FloatVal. -func NewFloatVal(in []byte) *SQLVal { - return &SQLVal{Type: FloatVal, Val: in} -} - -// NewHexNum builds a new HexNum. -func NewHexNum(in []byte) *SQLVal { - return &SQLVal{Type: HexNum, Val: in} -} - -// NewHexVal builds a new HexVal. -func NewHexVal(in []byte) *SQLVal { - return &SQLVal{Type: HexVal, Val: in} -} - -// NewBitVal builds a new BitVal containing a bit literal. -func NewBitVal(in []byte) *SQLVal { - return &SQLVal{Type: BitVal, Val: in} -} - -// NewValArg builds a new ValArg. -func NewValArg(in []byte) *SQLVal { - return &SQLVal{Type: ValArg, Val: in} -} - -// Format formats the node. -func (node *SQLVal) Format(buf *TrackedBuffer) { - switch node.Type { - case StrVal: - sqltypes.MakeTrusted(sqltypes.VarBinary, node.Val).EncodeSQL(buf) - case IntVal, FloatVal, HexNum: - buf.Myprintf("%s", []byte(node.Val)) - case HexVal: - buf.Myprintf("X'%s'", []byte(node.Val)) - case BitVal: - buf.Myprintf("B'%s'", []byte(node.Val)) - case ValArg: - buf.WriteArg(string(node.Val)) - default: - panic("unexpected") - } -} - -func (node *SQLVal) walkSubtree(visit Visit) error { - return nil -} - -func (node *SQLVal) replace(from, to Expr) bool { - return false -} - -// HexDecode decodes the hexval into bytes. -func (node *SQLVal) HexDecode() ([]byte, error) { - dst := make([]byte, hex.DecodedLen(len([]byte(node.Val)))) - _, err := hex.Decode(dst, []byte(node.Val)) - if err != nil { - return nil, err - } - return dst, err -} - -// NullVal represents a NULL value. -type NullVal struct{} - -// Format formats the node. -func (node *NullVal) Format(buf *TrackedBuffer) { - buf.Myprintf("null") -} - -func (node *NullVal) walkSubtree(visit Visit) error { - return nil -} - -func (node *NullVal) replace(from, to Expr) bool { - return false -} - -// BoolVal is true or false. -type BoolVal bool - -// Format formats the node. -func (node BoolVal) Format(buf *TrackedBuffer) { - if node { - buf.Myprintf("true") - } else { - buf.Myprintf("false") - } -} - -func (node BoolVal) walkSubtree(visit Visit) error { - return nil -} - -func (node BoolVal) replace(from, to Expr) bool { - return false -} - -// ColName represents a column name. -type ColName struct { - // Metadata is not populated by the parser. - // It's a placeholder for analyzers to store - // additional data, typically info about which - // table or column this node references. - Metadata interface{} - Name ColIdent - Qualifier TableName -} - -// Format formats the node. -func (node *ColName) Format(buf *TrackedBuffer) { - if !node.Qualifier.IsEmpty() { - buf.Myprintf("%v.", node.Qualifier) - } - buf.Myprintf("%v", node.Name) -} - -func (node *ColName) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - node.Qualifier, - ) -} - -func (node *ColName) replace(from, to Expr) bool { - return false -} - -// Equal returns true if the column names match. -func (node *ColName) Equal(c *ColName) bool { - // Failsafe: ColName should not be empty. - if node == nil || c == nil { - return false - } - return node.Name.Equal(c.Name) && node.Qualifier == c.Qualifier -} - -// ColTuple represents a list of column values. -// It can be ValTuple, Subquery, ListArg. -type ColTuple interface { - iColTuple() - Expr -} - -func (ValTuple) iColTuple() {} -func (*Subquery) iColTuple() {} -func (ListArg) iColTuple() {} - -// ValTuple represents a tuple of actual values. -type ValTuple Exprs - -// Format formats the node. -func (node ValTuple) Format(buf *TrackedBuffer) { - buf.Myprintf("(%v)", Exprs(node)) -} - -func (node ValTuple) walkSubtree(visit Visit) error { - return Walk(visit, Exprs(node)) -} - -func (node ValTuple) replace(from, to Expr) bool { - for i := range node { - if replaceExprs(from, to, &node[i]) { - return true - } - } - return false -} - -// Subquery represents a subquery. -type Subquery struct { - Select SelectStatement -} - -// Format formats the node. -func (node *Subquery) Format(buf *TrackedBuffer) { - buf.Myprintf("(%v)", node.Select) -} - -func (node *Subquery) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Select, - ) -} - -func (node *Subquery) replace(from, to Expr) bool { - return false -} - -// ListArg represents a named list argument. -type ListArg []byte - -// Format formats the node. -func (node ListArg) Format(buf *TrackedBuffer) { - buf.WriteArg(string(node)) -} - -func (node ListArg) walkSubtree(visit Visit) error { - return nil -} - -func (node ListArg) replace(from, to Expr) bool { - return false -} - -// BinaryExpr represents a binary value expression. -type BinaryExpr struct { - Operator string - Left, Right Expr -} - -// BinaryExpr.Operator -const ( - BitAndStr = "&" - BitOrStr = "|" - BitXorStr = "^" - PlusStr = "+" - MinusStr = "-" - MultStr = "*" - DivStr = "/" - IntDivStr = "div" - ModStr = "%" - ShiftLeftStr = "<<" - ShiftRightStr = ">>" -) - -// Format formats the node. -func (node *BinaryExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v %s %v", node.Left, node.Operator, node.Right) -} - -func (node *BinaryExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Left, - node.Right, - ) -} - -func (node *BinaryExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Left, &node.Right) -} - -// UnaryExpr represents a unary value expression. -type UnaryExpr struct { - Operator string - Expr Expr -} - -// UnaryExpr.Operator -const ( - UPlusStr = "+" - UMinusStr = "-" - TildaStr = "~" - BangStr = "!" - BinaryStr = "binary " - UBinaryStr = "_binary " -) - -// Format formats the node. -func (node *UnaryExpr) Format(buf *TrackedBuffer) { - if _, unary := node.Expr.(*UnaryExpr); unary { - buf.Myprintf("%s %v", node.Operator, node.Expr) - return - } - buf.Myprintf("%s%v", node.Operator, node.Expr) -} - -func (node *UnaryExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *UnaryExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// IntervalExpr represents a date-time INTERVAL expression. -type IntervalExpr struct { - Expr Expr - Unit string -} - -// Format formats the node. -func (node *IntervalExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("interval %v %s", node.Expr, node.Unit) -} - -func (node *IntervalExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *IntervalExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// CollateExpr represents dynamic collate operator. -type CollateExpr struct { - Expr Expr - Charset string -} - -// Format formats the node. -func (node *CollateExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v collate %s", node.Expr, node.Charset) -} - -func (node *CollateExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *CollateExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// FuncExpr represents a function call. -type FuncExpr struct { - Qualifier TableIdent - Name ColIdent - Distinct bool - Exprs SelectExprs -} - -// Format formats the node. -func (node *FuncExpr) Format(buf *TrackedBuffer) { - var distinct string - if node.Distinct { - distinct = "distinct " - } - if !node.Qualifier.IsEmpty() { - buf.Myprintf("%v.", node.Qualifier) - } - // Function names should not be back-quoted even - // if they match a reserved word. So, print the - // name as is. - buf.Myprintf("%s(%s%v)", node.Name.String(), distinct, node.Exprs) -} - -func (node *FuncExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Qualifier, - node.Name, - node.Exprs, - ) -} - -func (node *FuncExpr) replace(from, to Expr) bool { - for _, sel := range node.Exprs { - aliased, ok := sel.(*AliasedExpr) - if !ok { - continue - } - if replaceExprs(from, to, &aliased.Expr) { - return true - } - } - return false -} - -// Aggregates is a map of all aggregate functions. -var Aggregates = map[string]bool{ - "avg": true, - "bit_and": true, - "bit_or": true, - "bit_xor": true, - "count": true, - "group_concat": true, - "max": true, - "min": true, - "std": true, - "stddev_pop": true, - "stddev_samp": true, - "stddev": true, - "sum": true, - "var_pop": true, - "var_samp": true, - "variance": true, -} - -// IsAggregate returns true if the function is an aggregate. -func (node *FuncExpr) IsAggregate() bool { - return Aggregates[node.Name.Lowered()] -} - -// GroupConcatExpr represents a call to GROUP_CONCAT -type GroupConcatExpr struct { - Distinct string - Exprs SelectExprs - OrderBy OrderBy - Separator string -} - -// Format formats the node -func (node *GroupConcatExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("group_concat(%s%v%v%s)", node.Distinct, node.Exprs, node.OrderBy, node.Separator) -} - -func (node *GroupConcatExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Exprs, - node.OrderBy, - ) -} - -func (node *GroupConcatExpr) replace(from, to Expr) bool { - for _, sel := range node.Exprs { - aliased, ok := sel.(*AliasedExpr) - if !ok { - continue - } - if replaceExprs(from, to, &aliased.Expr) { - return true - } - } - for _, order := range node.OrderBy { - if replaceExprs(from, to, &order.Expr) { - return true - } - } - return false -} - -// ValuesFuncExpr represents a function call. -type ValuesFuncExpr struct { - Name *ColName -} - -// Format formats the node. -func (node *ValuesFuncExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("values(%v)", node.Name) -} - -func (node *ValuesFuncExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - ) -} - -func (node *ValuesFuncExpr) replace(from, to Expr) bool { - return false -} - -// SubstrExpr represents a call to SubstrExpr(column, value_expression) or SubstrExpr(column, value_expression,value_expression) -// also supported syntax SubstrExpr(column from value_expression for value_expression) -type SubstrExpr struct { - Name *ColName - From Expr - To Expr -} - -// Format formats the node. -func (node *SubstrExpr) Format(buf *TrackedBuffer) { - - if node.To == nil { - buf.Myprintf("substr(%v, %v)", node.Name, node.From) - } else { - buf.Myprintf("substr(%v, %v, %v)", node.Name, node.From, node.To) - } -} - -func (node *SubstrExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.From, &node.To) -} - -func (node *SubstrExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - node.From, - node.To, - ) -} - -// ConvertExpr represents a call to CONVERT(expr, type) -// or it's equivalent CAST(expr AS type). Both are rewritten to the former. -type ConvertExpr struct { - Expr Expr - Type *ConvertType -} - -// Format formats the node. -func (node *ConvertExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("convert(%v, %v)", node.Expr, node.Type) -} - -func (node *ConvertExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - node.Type, - ) -} - -func (node *ConvertExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// ConvertUsingExpr represents a call to CONVERT(expr USING charset). -type ConvertUsingExpr struct { - Expr Expr - Type string -} - -// Format formats the node. -func (node *ConvertUsingExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("convert(%v using %s)", node.Expr, node.Type) -} - -func (node *ConvertUsingExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -func (node *ConvertUsingExpr) replace(from, to Expr) bool { - return replaceExprs(from, to, &node.Expr) -} - -// ConvertType represents the type in call to CONVERT(expr, type) -type ConvertType struct { - Type string - Length *SQLVal - Scale *SQLVal - Operator string - Charset string -} - -// this string is "character set" and this comment is required -const ( - CharacterSetStr = " character set" -) - -// Format formats the node. -func (node *ConvertType) Format(buf *TrackedBuffer) { - buf.Myprintf("%s", node.Type) - if node.Length != nil { - buf.Myprintf("(%v", node.Length) - if node.Scale != nil { - buf.Myprintf(", %v", node.Scale) - } - buf.Myprintf(")") - } - if node.Charset != "" { - buf.Myprintf("%s %s", node.Operator, node.Charset) - } -} - -func (node *ConvertType) walkSubtree(visit Visit) error { - return nil -} - -// MatchExpr represents a call to the MATCH function -type MatchExpr struct { - Columns SelectExprs - Expr Expr - Option string -} - -// MatchExpr.Option -const ( - BooleanModeStr = " in boolean mode" - NaturalLanguageModeStr = " in natural language mode" - NaturalLanguageModeWithQueryExpansionStr = " in natural language mode with query expansion" - QueryExpansionStr = " with query expansion" -) - -// Format formats the node -func (node *MatchExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("match(%v) against (%v%s)", node.Columns, node.Expr, node.Option) -} - -func (node *MatchExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Columns, - node.Expr, - ) -} - -func (node *MatchExpr) replace(from, to Expr) bool { - for _, sel := range node.Columns { - aliased, ok := sel.(*AliasedExpr) - if !ok { - continue - } - if replaceExprs(from, to, &aliased.Expr) { - return true - } - } - return replaceExprs(from, to, &node.Expr) -} - -// CaseExpr represents a CASE expression. -type CaseExpr struct { - Expr Expr - Whens []*When - Else Expr -} - -// Format formats the node. -func (node *CaseExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("case ") - if node.Expr != nil { - buf.Myprintf("%v ", node.Expr) - } - for _, when := range node.Whens { - buf.Myprintf("%v ", when) - } - if node.Else != nil { - buf.Myprintf("else %v ", node.Else) - } - buf.Myprintf("end") -} - -func (node *CaseExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - if err := Walk(visit, node.Expr); err != nil { - return err - } - for _, n := range node.Whens { - if err := Walk(visit, n); err != nil { - return err - } - } - return Walk(visit, node.Else) -} - -func (node *CaseExpr) replace(from, to Expr) bool { - for _, when := range node.Whens { - if replaceExprs(from, to, &when.Cond, &when.Val) { - return true - } - } - return replaceExprs(from, to, &node.Expr, &node.Else) -} - -// Default represents a DEFAULT expression. -type Default struct { - ColName string -} - -// Format formats the node. -func (node *Default) Format(buf *TrackedBuffer) { - buf.Myprintf("default") - if node.ColName != "" { - buf.Myprintf("(%s)", node.ColName) - } -} - -func (node *Default) walkSubtree(visit Visit) error { - return nil -} - -func (node *Default) replace(from, to Expr) bool { - return false -} - -// When represents a WHEN sub-expression. -type When struct { - Cond Expr - Val Expr -} - -// Format formats the node. -func (node *When) Format(buf *TrackedBuffer) { - buf.Myprintf("when %v then %v", node.Cond, node.Val) -} - -func (node *When) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Cond, - node.Val, - ) -} - -// GroupBy represents a GROUP BY clause. -type GroupBy []Expr - -// Format formats the node. -func (node GroupBy) Format(buf *TrackedBuffer) { - prefix := " group by " - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node GroupBy) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// OrderBy represents an ORDER By clause. -type OrderBy []*Order - -// Format formats the node. -func (node OrderBy) Format(buf *TrackedBuffer) { - prefix := " order by " - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node OrderBy) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// Order represents an ordering expression. -type Order struct { - Expr Expr - Direction string -} - -// Order.Direction -const ( - AscScr = "asc" - DescScr = "desc" -) - -// Format formats the node. -func (node *Order) Format(buf *TrackedBuffer) { - if node, ok := node.Expr.(*NullVal); ok { - buf.Myprintf("%v", node) - return - } - if node, ok := node.Expr.(*FuncExpr); ok { - if node.Name.Lowered() == "rand" { - buf.Myprintf("%v", node) - return - } - } - - buf.Myprintf("%v %s", node.Expr, node.Direction) -} - -func (node *Order) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Expr, - ) -} - -// Limit represents a LIMIT clause. -type Limit struct { - Offset, Rowcount Expr -} - -// Format formats the node. -func (node *Limit) Format(buf *TrackedBuffer) { - if node == nil { - return - } - buf.Myprintf(" limit ") - if node.Offset != nil { - buf.Myprintf("%v, ", node.Offset) - } - buf.Myprintf("%v", node.Rowcount) -} - -func (node *Limit) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Offset, - node.Rowcount, - ) -} - -// Values represents a VALUES clause. -type Values []ValTuple - -// Format formats the node. -func (node Values) Format(buf *TrackedBuffer) { - prefix := "values " - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node Values) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// UpdateExprs represents a list of update expressions. -type UpdateExprs []*UpdateExpr - -// Format formats the node. -func (node UpdateExprs) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node UpdateExprs) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// UpdateExpr represents an update expression. -type UpdateExpr struct { - Name *ColName - Expr Expr -} - -// Format formats the node. -func (node *UpdateExpr) Format(buf *TrackedBuffer) { - buf.Myprintf("%v = %v", node.Name, node.Expr) -} - -func (node *UpdateExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - node.Expr, - ) -} - -// SetExprs represents a list of set expressions. -type SetExprs []*SetExpr - -// Format formats the node. -func (node SetExprs) Format(buf *TrackedBuffer) { - var prefix string - for _, n := range node { - buf.Myprintf("%s%v", prefix, n) - prefix = ", " - } -} - -func (node SetExprs) walkSubtree(visit Visit) error { - for _, n := range node { - if err := Walk(visit, n); err != nil { - return err - } - } - return nil -} - -// SetExpr represents a set expression. -type SetExpr struct { - Name ColIdent - Expr Expr -} - -// Format formats the node. -func (node *SetExpr) Format(buf *TrackedBuffer) { - // We don't have to backtick set variable names. - if node.Name.EqualString("charset") || node.Name.EqualString("names") { - buf.Myprintf("%s %v", node.Name.String(), node.Expr) - } else { - buf.Myprintf("%s = %v", node.Name.String(), node.Expr) - } -} - -func (node *SetExpr) walkSubtree(visit Visit) error { - if node == nil { - return nil - } - return Walk( - visit, - node.Name, - node.Expr, - ) -} - -// OnDup represents an ON DUPLICATE KEY clause. -type OnDup UpdateExprs - -// Format formats the node. -func (node OnDup) Format(buf *TrackedBuffer) { - if node == nil { - return - } - buf.Myprintf(" on duplicate key update %v", UpdateExprs(node)) -} - -func (node OnDup) walkSubtree(visit Visit) error { - return Walk(visit, UpdateExprs(node)) -} - -// ColIdent is a case insensitive SQL identifier. It will be escaped with -// backquotes if necessary. -type ColIdent struct { - // This artifact prevents this struct from being compared - // with itself. It consumes no space as long as it's not the - // last field in the struct. - _ [0]struct{ _ []byte } - val, lowered string -} - -// NewColIdent makes a new ColIdent. -func NewColIdent(str string) ColIdent { - return ColIdent{ - val: str, - } -} - -// Format formats the node. -func (node ColIdent) Format(buf *TrackedBuffer) { - formatID(buf, node.val, node.Lowered()) -} - -func (node ColIdent) walkSubtree(visit Visit) error { - return nil -} - -// IsEmpty returns true if the name is empty. -func (node ColIdent) IsEmpty() bool { - return node.val == "" -} - -// String returns the unescaped column name. It must -// not be used for SQL generation. Use sqlparser.String -// instead. The Stringer conformance is for usage -// in templates. -func (node ColIdent) String() string { - return node.val -} - -// CompliantName returns a compliant id name -// that can be used for a bind var. -func (node ColIdent) CompliantName() string { - return compliantName(node.val) -} - -// Lowered returns a lower-cased column name. -// This function should generally be used only for optimizing -// comparisons. -func (node ColIdent) Lowered() string { - if node.val == "" { - return "" - } - if node.lowered == "" { - node.lowered = strings.ToLower(node.val) - } - return node.lowered -} - -// Equal performs a case-insensitive compare. -func (node ColIdent) Equal(in ColIdent) bool { - return node.Lowered() == in.Lowered() -} - -// EqualString performs a case-insensitive compare with str. -func (node ColIdent) EqualString(str string) bool { - return node.Lowered() == strings.ToLower(str) -} - -// MarshalJSON marshals into JSON. -func (node ColIdent) MarshalJSON() ([]byte, error) { - return json.Marshal(node.val) -} - -// UnmarshalJSON unmarshals from JSON. -func (node *ColIdent) UnmarshalJSON(b []byte) error { - var result string - err := json.Unmarshal(b, &result) - if err != nil { - return err - } - node.val = result - return nil -} - -// TableIdent is a case sensitive SQL identifier. It will be escaped with -// backquotes if necessary. -type TableIdent struct { - v string -} - -// NewTableIdent creates a new TableIdent. -func NewTableIdent(str string) TableIdent { - return TableIdent{v: str} -} - -// Format formats the node. -func (node TableIdent) Format(buf *TrackedBuffer) { - formatID(buf, node.v, strings.ToLower(node.v)) -} - -func (node TableIdent) walkSubtree(visit Visit) error { - return nil -} - -// IsEmpty returns true if TabIdent is empty. -func (node TableIdent) IsEmpty() bool { - return node.v == "" -} - -// String returns the unescaped table name. It must -// not be used for SQL generation. Use sqlparser.String -// instead. The Stringer conformance is for usage -// in templates. -func (node TableIdent) String() string { - return node.v -} - -// CompliantName returns a compliant id name -// that can be used for a bind var. -func (node TableIdent) CompliantName() string { - return compliantName(node.v) -} - -// MarshalJSON marshals into JSON. -func (node TableIdent) MarshalJSON() ([]byte, error) { - return json.Marshal(node.v) -} - -// UnmarshalJSON unmarshals from JSON. -func (node *TableIdent) UnmarshalJSON(b []byte) error { - var result string - err := json.Unmarshal(b, &result) - if err != nil { - return err - } - node.v = result - return nil -} - -// Backtick produces a backticked literal given an input string. -func Backtick(in string) string { - var buf bytes.Buffer - buf.WriteByte('`') - for _, c := range in { - buf.WriteRune(c) - if c == '`' { - buf.WriteByte('`') - } - } - buf.WriteByte('`') - return buf.String() -} - -func formatID(buf *TrackedBuffer, original, lowered string) { - isDbSystemVariable := false - if len(original) > 1 && original[:2] == "@@" { - isDbSystemVariable = true - } - - for i, c := range original { - if !isLetter(uint16(c)) && (!isDbSystemVariable || !isCarat(uint16(c))) { - if i == 0 || !isDigit(uint16(c)) { - goto mustEscape - } - } - } - if _, ok := keywords[lowered]; ok { - goto mustEscape - } - buf.Myprintf("%s", original) - return - -mustEscape: - buf.WriteByte('`') - for _, c := range original { - buf.WriteRune(c) - if c == '`' { - buf.WriteByte('`') - } - } - buf.WriteByte('`') -} - -func compliantName(in string) string { - var buf bytes.Buffer - for i, c := range in { - if !isLetter(uint16(c)) { - if i == 0 || !isDigit(uint16(c)) { - buf.WriteByte('_') - continue - } - } - buf.WriteRune(c) - } - return buf.String() -} diff --git a/vendor/github.com/xwb1989/sqlparser/comments.go b/vendor/github.com/xwb1989/sqlparser/comments.go deleted file mode 100644 index a0f7f1b45..000000000 --- a/vendor/github.com/xwb1989/sqlparser/comments.go +++ /dev/null @@ -1,293 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "strconv" - "strings" - "unicode" -) - -const ( - // DirectiveMultiShardAutocommit is the query comment directive to allow - // single round trip autocommit with a multi-shard statement. - DirectiveMultiShardAutocommit = "MULTI_SHARD_AUTOCOMMIT" - // DirectiveSkipQueryPlanCache skips query plan cache when set. - DirectiveSkipQueryPlanCache = "SKIP_QUERY_PLAN_CACHE" - // DirectiveQueryTimeout sets a query timeout in vtgate. Only supported for SELECTS. - DirectiveQueryTimeout = "QUERY_TIMEOUT_MS" -) - -func isNonSpace(r rune) bool { - return !unicode.IsSpace(r) -} - -// leadingCommentEnd returns the first index after all leading comments, or -// 0 if there are no leading comments. -func leadingCommentEnd(text string) (end int) { - hasComment := false - pos := 0 - for pos < len(text) { - // Eat up any whitespace. Trailing whitespace will be considered part of - // the leading comments. - nextVisibleOffset := strings.IndexFunc(text[pos:], isNonSpace) - if nextVisibleOffset < 0 { - break - } - pos += nextVisibleOffset - remainingText := text[pos:] - - // Found visible characters. Look for '/*' at the beginning - // and '*/' somewhere after that. - if len(remainingText) < 4 || remainingText[:2] != "/*" { - break - } - commentLength := 4 + strings.Index(remainingText[2:], "*/") - if commentLength < 4 { - // Missing end comment :/ - break - } - - hasComment = true - pos += commentLength - } - - if hasComment { - return pos - } - return 0 -} - -// trailingCommentStart returns the first index of trailing comments. -// If there are no trailing comments, returns the length of the input string. -func trailingCommentStart(text string) (start int) { - hasComment := false - reducedLen := len(text) - for reducedLen > 0 { - // Eat up any whitespace. Leading whitespace will be considered part of - // the trailing comments. - nextReducedLen := strings.LastIndexFunc(text[:reducedLen], isNonSpace) + 1 - if nextReducedLen == 0 { - break - } - reducedLen = nextReducedLen - if reducedLen < 4 || text[reducedLen-2:reducedLen] != "*/" { - break - } - - // Find the beginning of the comment - startCommentPos := strings.LastIndex(text[:reducedLen-2], "/*") - if startCommentPos < 0 { - // Badly formatted sql :/ - break - } - - hasComment = true - reducedLen = startCommentPos - } - - if hasComment { - return reducedLen - } - return len(text) -} - -// MarginComments holds the leading and trailing comments that surround a query. -type MarginComments struct { - Leading string - Trailing string -} - -// SplitMarginComments pulls out any leading or trailing comments from a raw sql query. -// This function also trims leading (if there's a comment) and trailing whitespace. -func SplitMarginComments(sql string) (query string, comments MarginComments) { - trailingStart := trailingCommentStart(sql) - leadingEnd := leadingCommentEnd(sql[:trailingStart]) - comments = MarginComments{ - Leading: strings.TrimLeftFunc(sql[:leadingEnd], unicode.IsSpace), - Trailing: strings.TrimRightFunc(sql[trailingStart:], unicode.IsSpace), - } - return strings.TrimFunc(sql[leadingEnd:trailingStart], unicode.IsSpace), comments -} - -// StripLeadingComments trims the SQL string and removes any leading comments -func StripLeadingComments(sql string) string { - sql = strings.TrimFunc(sql, unicode.IsSpace) - - for hasCommentPrefix(sql) { - switch sql[0] { - case '/': - // Multi line comment - index := strings.Index(sql, "*/") - if index <= 1 { - return sql - } - // don't strip /*! ... */ or /*!50700 ... */ - if len(sql) > 2 && sql[2] == '!' { - return sql - } - sql = sql[index+2:] - case '-': - // Single line comment - index := strings.Index(sql, "\n") - if index == -1 { - return sql - } - sql = sql[index+1:] - } - - sql = strings.TrimFunc(sql, unicode.IsSpace) - } - - return sql -} - -func hasCommentPrefix(sql string) bool { - return len(sql) > 1 && ((sql[0] == '/' && sql[1] == '*') || (sql[0] == '-' && sql[1] == '-')) -} - -// ExtractMysqlComment extracts the version and SQL from a comment-only query -// such as /*!50708 sql here */ -func ExtractMysqlComment(sql string) (version string, innerSQL string) { - sql = sql[3 : len(sql)-2] - - digitCount := 0 - endOfVersionIndex := strings.IndexFunc(sql, func(c rune) bool { - digitCount++ - return !unicode.IsDigit(c) || digitCount == 6 - }) - version = sql[0:endOfVersionIndex] - innerSQL = strings.TrimFunc(sql[endOfVersionIndex:], unicode.IsSpace) - - return version, innerSQL -} - -const commentDirectivePreamble = "/*vt+" - -// CommentDirectives is the parsed representation for execution directives -// conveyed in query comments -type CommentDirectives map[string]interface{} - -// ExtractCommentDirectives parses the comment list for any execution directives -// of the form: -// -// /*vt+ OPTION_ONE=1 OPTION_TWO OPTION_THREE=abcd */ -// -// It returns the map of the directive values or nil if there aren't any. -func ExtractCommentDirectives(comments Comments) CommentDirectives { - if comments == nil { - return nil - } - - var vals map[string]interface{} - - for _, comment := range comments { - commentStr := string(comment) - if commentStr[0:5] != commentDirectivePreamble { - continue - } - - if vals == nil { - vals = make(map[string]interface{}) - } - - // Split on whitespace and ignore the first and last directive - // since they contain the comment start/end - directives := strings.Fields(commentStr) - for i := 1; i < len(directives)-1; i++ { - directive := directives[i] - sep := strings.IndexByte(directive, '=') - - // No value is equivalent to a true boolean - if sep == -1 { - vals[directive] = true - continue - } - - strVal := directive[sep+1:] - directive = directive[:sep] - - intVal, err := strconv.Atoi(strVal) - if err == nil { - vals[directive] = intVal - continue - } - - boolVal, err := strconv.ParseBool(strVal) - if err == nil { - vals[directive] = boolVal - continue - } - - vals[directive] = strVal - } - } - return vals -} - -// IsSet checks the directive map for the named directive and returns -// true if the directive is set and has a true/false or 0/1 value -func (d CommentDirectives) IsSet(key string) bool { - if d == nil { - return false - } - - val, ok := d[key] - if !ok { - return false - } - - boolVal, ok := val.(bool) - if ok { - return boolVal - } - - intVal, ok := val.(int) - if ok { - return intVal == 1 - } - return false -} - -// SkipQueryPlanCacheDirective returns true if skip query plan cache directive is set to true in query. -func SkipQueryPlanCacheDirective(stmt Statement) bool { - switch stmt := stmt.(type) { - case *Select: - directives := ExtractCommentDirectives(stmt.Comments) - if directives.IsSet(DirectiveSkipQueryPlanCache) { - return true - } - case *Insert: - directives := ExtractCommentDirectives(stmt.Comments) - if directives.IsSet(DirectiveSkipQueryPlanCache) { - return true - } - case *Update: - directives := ExtractCommentDirectives(stmt.Comments) - if directives.IsSet(DirectiveSkipQueryPlanCache) { - return true - } - case *Delete: - directives := ExtractCommentDirectives(stmt.Comments) - if directives.IsSet(DirectiveSkipQueryPlanCache) { - return true - } - default: - return false - } - return false -} diff --git a/vendor/github.com/xwb1989/sqlparser/encodable.go b/vendor/github.com/xwb1989/sqlparser/encodable.go deleted file mode 100644 index badfa42dd..000000000 --- a/vendor/github.com/xwb1989/sqlparser/encodable.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "bytes" - - "github.com/xwb1989/sqlparser/dependency/sqltypes" -) - -// This file contains types that are 'Encodable'. - -// Encodable defines the interface for types that can -// be custom-encoded into SQL. -type Encodable interface { - EncodeSQL(buf *bytes.Buffer) -} - -// InsertValues is a custom SQL encoder for the values of -// an insert statement. -type InsertValues [][]sqltypes.Value - -// EncodeSQL performs the SQL encoding for InsertValues. -func (iv InsertValues) EncodeSQL(buf *bytes.Buffer) { - for i, rows := range iv { - if i != 0 { - buf.WriteString(", ") - } - buf.WriteByte('(') - for j, bv := range rows { - if j != 0 { - buf.WriteString(", ") - } - bv.EncodeSQL(buf) - } - buf.WriteByte(')') - } -} - -// TupleEqualityList is for generating equality constraints -// for tables that have composite primary keys. -type TupleEqualityList struct { - Columns []ColIdent - Rows [][]sqltypes.Value -} - -// EncodeSQL generates the where clause constraints for the tuple -// equality. -func (tpl *TupleEqualityList) EncodeSQL(buf *bytes.Buffer) { - if len(tpl.Columns) == 1 { - tpl.encodeAsIn(buf) - return - } - tpl.encodeAsEquality(buf) -} - -func (tpl *TupleEqualityList) encodeAsIn(buf *bytes.Buffer) { - Append(buf, tpl.Columns[0]) - buf.WriteString(" in (") - for i, r := range tpl.Rows { - if i != 0 { - buf.WriteString(", ") - } - r[0].EncodeSQL(buf) - } - buf.WriteByte(')') -} - -func (tpl *TupleEqualityList) encodeAsEquality(buf *bytes.Buffer) { - for i, r := range tpl.Rows { - if i != 0 { - buf.WriteString(" or ") - } - buf.WriteString("(") - for j, c := range tpl.Columns { - if j != 0 { - buf.WriteString(" and ") - } - Append(buf, c) - buf.WriteString(" = ") - r[j].EncodeSQL(buf) - } - buf.WriteByte(')') - } -} diff --git a/vendor/github.com/xwb1989/sqlparser/impossible_query.go b/vendor/github.com/xwb1989/sqlparser/impossible_query.go deleted file mode 100644 index 1179b6112..000000000 --- a/vendor/github.com/xwb1989/sqlparser/impossible_query.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreedto in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -// FormatImpossibleQuery creates an impossible query in a TrackedBuffer. -// An impossible query is a modified version of a query where all selects have where clauses that are -// impossible for mysql to resolve. This is used in the vtgate and vttablet: -// -// - In the vtgate it's used for joins: if the first query returns no result, then vtgate uses the impossible -// query just to fetch field info from vttablet -// - In the vttablet, it's just an optimization: the field info is fetched once form MySQL, cached and reused -// for subsequent queries -func FormatImpossibleQuery(buf *TrackedBuffer, node SQLNode) { - switch node := node.(type) { - case *Select: - buf.Myprintf("select %v from %v where 1 != 1", node.SelectExprs, node.From) - if node.GroupBy != nil { - node.GroupBy.Format(buf) - } - case *Union: - buf.Myprintf("%v %s %v", node.Left, node.Type, node.Right) - default: - node.Format(buf) - } -} diff --git a/vendor/github.com/xwb1989/sqlparser/normalizer.go b/vendor/github.com/xwb1989/sqlparser/normalizer.go deleted file mode 100644 index f6520316a..000000000 --- a/vendor/github.com/xwb1989/sqlparser/normalizer.go +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "fmt" - - "github.com/xwb1989/sqlparser/dependency/sqltypes" - - "github.com/xwb1989/sqlparser/dependency/querypb" -) - -// Normalize changes the statement to use bind values, and -// updates the bind vars to those values. The supplied prefix -// is used to generate the bind var names. The function ensures -// that there are no collisions with existing bind vars. -// Within Select constructs, bind vars are deduped. This allows -// us to identify vindex equality. Otherwise, every value is -// treated as distinct. -func Normalize(stmt Statement, bindVars map[string]*querypb.BindVariable, prefix string) { - nz := newNormalizer(stmt, bindVars, prefix) - _ = Walk(nz.WalkStatement, stmt) -} - -type normalizer struct { - stmt Statement - bindVars map[string]*querypb.BindVariable - prefix string - reserved map[string]struct{} - counter int - vals map[string]string -} - -func newNormalizer(stmt Statement, bindVars map[string]*querypb.BindVariable, prefix string) *normalizer { - return &normalizer{ - stmt: stmt, - bindVars: bindVars, - prefix: prefix, - reserved: GetBindvars(stmt), - counter: 1, - vals: make(map[string]string), - } -} - -// WalkStatement is the top level walk function. -// If it encounters a Select, it switches to a mode -// where variables are deduped. -func (nz *normalizer) WalkStatement(node SQLNode) (bool, error) { - switch node := node.(type) { - case *Select: - _ = Walk(nz.WalkSelect, node) - // Don't continue - return false, nil - case *SQLVal: - nz.convertSQLVal(node) - case *ComparisonExpr: - nz.convertComparison(node) - } - return true, nil -} - -// WalkSelect normalizes the AST in Select mode. -func (nz *normalizer) WalkSelect(node SQLNode) (bool, error) { - switch node := node.(type) { - case *SQLVal: - nz.convertSQLValDedup(node) - case *ComparisonExpr: - nz.convertComparison(node) - } - return true, nil -} - -func (nz *normalizer) convertSQLValDedup(node *SQLVal) { - // If value is too long, don't dedup. - // Such values are most likely not for vindexes. - // We save a lot of CPU because we avoid building - // the key for them. - if len(node.Val) > 256 { - nz.convertSQLVal(node) - return - } - - // Make the bindvar - bval := nz.sqlToBindvar(node) - if bval == nil { - return - } - - // Check if there's a bindvar for that value already. - var key string - if bval.Type == sqltypes.VarBinary { - // Prefixing strings with "'" ensures that a string - // and number that have the same representation don't - // collide. - key = "'" + string(node.Val) - } else { - key = string(node.Val) - } - bvname, ok := nz.vals[key] - if !ok { - // If there's no such bindvar, make a new one. - bvname = nz.newName() - nz.vals[key] = bvname - nz.bindVars[bvname] = bval - } - - // Modify the AST node to a bindvar. - node.Type = ValArg - node.Val = append([]byte(":"), bvname...) -} - -// convertSQLVal converts an SQLVal without the dedup. -func (nz *normalizer) convertSQLVal(node *SQLVal) { - bval := nz.sqlToBindvar(node) - if bval == nil { - return - } - - bvname := nz.newName() - nz.bindVars[bvname] = bval - - node.Type = ValArg - node.Val = append([]byte(":"), bvname...) -} - -// convertComparison attempts to convert IN clauses to -// use the list bind var construct. If it fails, it returns -// with no change made. The walk function will then continue -// and iterate on converting each individual value into separate -// bind vars. -func (nz *normalizer) convertComparison(node *ComparisonExpr) { - if node.Operator != InStr && node.Operator != NotInStr { - return - } - tupleVals, ok := node.Right.(ValTuple) - if !ok { - return - } - // The RHS is a tuple of values. - // Make a list bindvar. - bvals := &querypb.BindVariable{ - Type: querypb.Type_TUPLE, - } - for _, val := range tupleVals { - bval := nz.sqlToBindvar(val) - if bval == nil { - return - } - bvals.Values = append(bvals.Values, &querypb.Value{ - Type: bval.Type, - Value: bval.Value, - }) - } - bvname := nz.newName() - nz.bindVars[bvname] = bvals - // Modify RHS to be a list bindvar. - node.Right = ListArg(append([]byte("::"), bvname...)) -} - -func (nz *normalizer) sqlToBindvar(node SQLNode) *querypb.BindVariable { - if node, ok := node.(*SQLVal); ok { - var v sqltypes.Value - var err error - switch node.Type { - case StrVal: - v, err = sqltypes.NewValue(sqltypes.VarBinary, node.Val) - case IntVal: - v, err = sqltypes.NewValue(sqltypes.Int64, node.Val) - case FloatVal: - v, err = sqltypes.NewValue(sqltypes.Float64, node.Val) - default: - return nil - } - if err != nil { - return nil - } - return sqltypes.ValueBindVariable(v) - } - return nil -} - -func (nz *normalizer) newName() string { - for { - newName := fmt.Sprintf("%s%d", nz.prefix, nz.counter) - if _, ok := nz.reserved[newName]; !ok { - nz.reserved[newName] = struct{}{} - return newName - } - nz.counter++ - } -} - -// GetBindvars returns a map of the bind vars referenced in the statement. -// TODO(sougou); This function gets called again from vtgate/planbuilder. -// Ideally, this should be done only once. -func GetBindvars(stmt Statement) map[string]struct{} { - bindvars := make(map[string]struct{}) - _ = Walk(func(node SQLNode) (kontinue bool, err error) { - switch node := node.(type) { - case *SQLVal: - if node.Type == ValArg { - bindvars[string(node.Val[1:])] = struct{}{} - } - case ListArg: - bindvars[string(node[2:])] = struct{}{} - } - return true, nil - }, stmt) - return bindvars -} diff --git a/vendor/github.com/xwb1989/sqlparser/parsed_query.go b/vendor/github.com/xwb1989/sqlparser/parsed_query.go deleted file mode 100644 index cf4ef03b6..000000000 --- a/vendor/github.com/xwb1989/sqlparser/parsed_query.go +++ /dev/null @@ -1,119 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "bytes" - "fmt" - - "github.com/xwb1989/sqlparser/dependency/querypb" - "github.com/xwb1989/sqlparser/dependency/sqltypes" -) - -// ParsedQuery represents a parsed query where -// bind locations are precompued for fast substitutions. -type ParsedQuery struct { - Query string - bindLocations []bindLocation -} - -type bindLocation struct { - offset, length int -} - -// NewParsedQuery returns a ParsedQuery of the ast. -func NewParsedQuery(node SQLNode) *ParsedQuery { - buf := NewTrackedBuffer(nil) - buf.Myprintf("%v", node) - return buf.ParsedQuery() -} - -// GenerateQuery generates a query by substituting the specified -// bindVariables. The extras parameter specifies special parameters -// that can perform custom encoding. -func (pq *ParsedQuery) GenerateQuery(bindVariables map[string]*querypb.BindVariable, extras map[string]Encodable) ([]byte, error) { - if len(pq.bindLocations) == 0 { - return []byte(pq.Query), nil - } - buf := bytes.NewBuffer(make([]byte, 0, len(pq.Query))) - current := 0 - for _, loc := range pq.bindLocations { - buf.WriteString(pq.Query[current:loc.offset]) - name := pq.Query[loc.offset : loc.offset+loc.length] - if encodable, ok := extras[name[1:]]; ok { - encodable.EncodeSQL(buf) - } else { - supplied, _, err := FetchBindVar(name, bindVariables) - if err != nil { - return nil, err - } - EncodeValue(buf, supplied) - } - current = loc.offset + loc.length - } - buf.WriteString(pq.Query[current:]) - return buf.Bytes(), nil -} - -// EncodeValue encodes one bind variable value into the query. -func EncodeValue(buf *bytes.Buffer, value *querypb.BindVariable) { - if value.Type != querypb.Type_TUPLE { - // Since we already check for TUPLE, we don't expect an error. - v, _ := sqltypes.BindVariableToValue(value) - v.EncodeSQL(buf) - return - } - - // It's a TUPLE. - buf.WriteByte('(') - for i, bv := range value.Values { - if i != 0 { - buf.WriteString(", ") - } - sqltypes.ProtoToValue(bv).EncodeSQL(buf) - } - buf.WriteByte(')') -} - -// FetchBindVar resolves the bind variable by fetching it from bindVariables. -func FetchBindVar(name string, bindVariables map[string]*querypb.BindVariable) (val *querypb.BindVariable, isList bool, err error) { - name = name[1:] - if name[0] == ':' { - name = name[1:] - isList = true - } - supplied, ok := bindVariables[name] - if !ok { - return nil, false, fmt.Errorf("missing bind var %s", name) - } - - if isList { - if supplied.Type != querypb.Type_TUPLE { - return nil, false, fmt.Errorf("unexpected list arg type (%v) for key %s", supplied.Type, name) - } - if len(supplied.Values) == 0 { - return nil, false, fmt.Errorf("empty list supplied for %s", name) - } - return supplied, true, nil - } - - if supplied.Type == querypb.Type_TUPLE { - return nil, false, fmt.Errorf("unexpected arg type (TUPLE) for non-list key %s", name) - } - - return supplied, false, nil -} diff --git a/vendor/github.com/xwb1989/sqlparser/redact_query.go b/vendor/github.com/xwb1989/sqlparser/redact_query.go deleted file mode 100644 index a50b9bcd3..000000000 --- a/vendor/github.com/xwb1989/sqlparser/redact_query.go +++ /dev/null @@ -1,19 +0,0 @@ -package sqlparser - -import querypb "github.com/xwb1989/sqlparser/dependency/querypb" - -// RedactSQLQuery returns a sql string with the params stripped out for display -func RedactSQLQuery(sql string) (string, error) { - bv := map[string]*querypb.BindVariable{} - sqlStripped, comments := SplitMarginComments(sql) - - stmt, err := Parse(sqlStripped) - if err != nil { - return "", err - } - - prefix := "redacted" - Normalize(stmt, bv, prefix) - - return comments.Leading + String(stmt) + comments.Trailing, nil -} diff --git a/vendor/github.com/xwb1989/sqlparser/sql.go b/vendor/github.com/xwb1989/sqlparser/sql.go deleted file mode 100644 index 4c8f2657f..000000000 --- a/vendor/github.com/xwb1989/sqlparser/sql.go +++ /dev/null @@ -1,6136 +0,0 @@ -//line sql.y:18 -package sqlparser - -import __yyfmt__ "fmt" - -//line sql.y:18 -func setParseTree(yylex interface{}, stmt Statement) { - yylex.(*Tokenizer).ParseTree = stmt -} - -func setAllowComments(yylex interface{}, allow bool) { - yylex.(*Tokenizer).AllowComments = allow -} - -func setDDL(yylex interface{}, ddl *DDL) { - yylex.(*Tokenizer).partialDDL = ddl -} - -func incNesting(yylex interface{}) bool { - yylex.(*Tokenizer).nesting++ - if yylex.(*Tokenizer).nesting == 200 { - return true - } - return false -} - -func decNesting(yylex interface{}) { - yylex.(*Tokenizer).nesting-- -} - -// forceEOF forces the lexer to end prematurely. Not all SQL statements -// are supported by the Parser, thus calling forceEOF will make the lexer -// return EOF early. -func forceEOF(yylex interface{}) { - yylex.(*Tokenizer).ForceEOF = true -} - -//line sql.y:53 -type yySymType struct { - yys int - empty struct{} - statement Statement - selStmt SelectStatement - ddl *DDL - ins *Insert - byt byte - bytes []byte - bytes2 [][]byte - str string - strs []string - selectExprs SelectExprs - selectExpr SelectExpr - columns Columns - partitions Partitions - colName *ColName - tableExprs TableExprs - tableExpr TableExpr - joinCondition JoinCondition - tableName TableName - tableNames TableNames - indexHints *IndexHints - expr Expr - exprs Exprs - boolVal BoolVal - colTuple ColTuple - values Values - valTuple ValTuple - subquery *Subquery - whens []*When - when *When - orderBy OrderBy - order *Order - limit *Limit - updateExprs UpdateExprs - setExprs SetExprs - updateExpr *UpdateExpr - setExpr *SetExpr - colIdent ColIdent - tableIdent TableIdent - convertType *ConvertType - aliasedTableName *AliasedTableExpr - TableSpec *TableSpec - columnType ColumnType - colKeyOpt ColumnKeyOption - optVal *SQLVal - LengthScaleOption LengthScaleOption - columnDefinition *ColumnDefinition - indexDefinition *IndexDefinition - indexInfo *IndexInfo - indexOption *IndexOption - indexOptions []*IndexOption - indexColumn *IndexColumn - indexColumns []*IndexColumn - partDefs []*PartitionDefinition - partDef *PartitionDefinition - partSpec *PartitionSpec - vindexParam VindexParam - vindexParams []VindexParam - showFilter *ShowFilter -} - -const LEX_ERROR = 57346 -const UNION = 57347 -const SELECT = 57348 -const STREAM = 57349 -const INSERT = 57350 -const UPDATE = 57351 -const DELETE = 57352 -const FROM = 57353 -const WHERE = 57354 -const GROUP = 57355 -const HAVING = 57356 -const ORDER = 57357 -const BY = 57358 -const LIMIT = 57359 -const OFFSET = 57360 -const FOR = 57361 -const ALL = 57362 -const DISTINCT = 57363 -const AS = 57364 -const EXISTS = 57365 -const ASC = 57366 -const DESC = 57367 -const INTO = 57368 -const DUPLICATE = 57369 -const KEY = 57370 -const DEFAULT = 57371 -const SET = 57372 -const LOCK = 57373 -const KEYS = 57374 -const VALUES = 57375 -const LAST_INSERT_ID = 57376 -const NEXT = 57377 -const VALUE = 57378 -const SHARE = 57379 -const MODE = 57380 -const SQL_NO_CACHE = 57381 -const SQL_CACHE = 57382 -const JOIN = 57383 -const STRAIGHT_JOIN = 57384 -const LEFT = 57385 -const RIGHT = 57386 -const INNER = 57387 -const OUTER = 57388 -const CROSS = 57389 -const NATURAL = 57390 -const USE = 57391 -const FORCE = 57392 -const ON = 57393 -const USING = 57394 -const ID = 57395 -const HEX = 57396 -const STRING = 57397 -const INTEGRAL = 57398 -const FLOAT = 57399 -const HEXNUM = 57400 -const VALUE_ARG = 57401 -const LIST_ARG = 57402 -const COMMENT = 57403 -const COMMENT_KEYWORD = 57404 -const BIT_LITERAL = 57405 -const NULL = 57406 -const TRUE = 57407 -const FALSE = 57408 -const OR = 57409 -const AND = 57410 -const NOT = 57411 -const BETWEEN = 57412 -const CASE = 57413 -const WHEN = 57414 -const THEN = 57415 -const ELSE = 57416 -const END = 57417 -const LE = 57418 -const GE = 57419 -const NE = 57420 -const NULL_SAFE_EQUAL = 57421 -const IS = 57422 -const LIKE = 57423 -const REGEXP = 57424 -const IN = 57425 -const SHIFT_LEFT = 57426 -const SHIFT_RIGHT = 57427 -const DIV = 57428 -const MOD = 57429 -const UNARY = 57430 -const COLLATE = 57431 -const BINARY = 57432 -const UNDERSCORE_BINARY = 57433 -const INTERVAL = 57434 -const JSON_EXTRACT_OP = 57435 -const JSON_UNQUOTE_EXTRACT_OP = 57436 -const CREATE = 57437 -const ALTER = 57438 -const DROP = 57439 -const RENAME = 57440 -const ANALYZE = 57441 -const ADD = 57442 -const SCHEMA = 57443 -const TABLE = 57444 -const INDEX = 57445 -const VIEW = 57446 -const TO = 57447 -const IGNORE = 57448 -const IF = 57449 -const UNIQUE = 57450 -const PRIMARY = 57451 -const COLUMN = 57452 -const CONSTRAINT = 57453 -const SPATIAL = 57454 -const FULLTEXT = 57455 -const FOREIGN = 57456 -const KEY_BLOCK_SIZE = 57457 -const SHOW = 57458 -const DESCRIBE = 57459 -const EXPLAIN = 57460 -const DATE = 57461 -const ESCAPE = 57462 -const REPAIR = 57463 -const OPTIMIZE = 57464 -const TRUNCATE = 57465 -const MAXVALUE = 57466 -const PARTITION = 57467 -const REORGANIZE = 57468 -const LESS = 57469 -const THAN = 57470 -const PROCEDURE = 57471 -const TRIGGER = 57472 -const VINDEX = 57473 -const VINDEXES = 57474 -const STATUS = 57475 -const VARIABLES = 57476 -const BEGIN = 57477 -const START = 57478 -const TRANSACTION = 57479 -const COMMIT = 57480 -const ROLLBACK = 57481 -const BIT = 57482 -const TINYINT = 57483 -const SMALLINT = 57484 -const MEDIUMINT = 57485 -const INT = 57486 -const INTEGER = 57487 -const BIGINT = 57488 -const INTNUM = 57489 -const REAL = 57490 -const DOUBLE = 57491 -const FLOAT_TYPE = 57492 -const DECIMAL = 57493 -const NUMERIC = 57494 -const TIME = 57495 -const TIMESTAMP = 57496 -const DATETIME = 57497 -const YEAR = 57498 -const CHAR = 57499 -const VARCHAR = 57500 -const BOOL = 57501 -const CHARACTER = 57502 -const VARBINARY = 57503 -const NCHAR = 57504 -const TEXT = 57505 -const TINYTEXT = 57506 -const MEDIUMTEXT = 57507 -const LONGTEXT = 57508 -const BLOB = 57509 -const TINYBLOB = 57510 -const MEDIUMBLOB = 57511 -const LONGBLOB = 57512 -const JSON = 57513 -const ENUM = 57514 -const GEOMETRY = 57515 -const POINT = 57516 -const LINESTRING = 57517 -const POLYGON = 57518 -const GEOMETRYCOLLECTION = 57519 -const MULTIPOINT = 57520 -const MULTILINESTRING = 57521 -const MULTIPOLYGON = 57522 -const NULLX = 57523 -const AUTO_INCREMENT = 57524 -const APPROXNUM = 57525 -const SIGNED = 57526 -const UNSIGNED = 57527 -const ZEROFILL = 57528 -const DATABASES = 57529 -const TABLES = 57530 -const VITESS_KEYSPACES = 57531 -const VITESS_SHARDS = 57532 -const VITESS_TABLETS = 57533 -const VSCHEMA_TABLES = 57534 -const EXTENDED = 57535 -const FULL = 57536 -const PROCESSLIST = 57537 -const NAMES = 57538 -const CHARSET = 57539 -const GLOBAL = 57540 -const SESSION = 57541 -const ISOLATION = 57542 -const LEVEL = 57543 -const READ = 57544 -const WRITE = 57545 -const ONLY = 57546 -const REPEATABLE = 57547 -const COMMITTED = 57548 -const UNCOMMITTED = 57549 -const SERIALIZABLE = 57550 -const CURRENT_TIMESTAMP = 57551 -const DATABASE = 57552 -const CURRENT_DATE = 57553 -const CURRENT_TIME = 57554 -const LOCALTIME = 57555 -const LOCALTIMESTAMP = 57556 -const UTC_DATE = 57557 -const UTC_TIME = 57558 -const UTC_TIMESTAMP = 57559 -const REPLACE = 57560 -const CONVERT = 57561 -const CAST = 57562 -const SUBSTR = 57563 -const SUBSTRING = 57564 -const GROUP_CONCAT = 57565 -const SEPARATOR = 57566 -const MATCH = 57567 -const AGAINST = 57568 -const BOOLEAN = 57569 -const LANGUAGE = 57570 -const WITH = 57571 -const QUERY = 57572 -const EXPANSION = 57573 -const UNUSED = 57574 - -var yyToknames = [...]string{ - "$end", - "error", - "$unk", - "LEX_ERROR", - "UNION", - "SELECT", - "STREAM", - "INSERT", - "UPDATE", - "DELETE", - "FROM", - "WHERE", - "GROUP", - "HAVING", - "ORDER", - "BY", - "LIMIT", - "OFFSET", - "FOR", - "ALL", - "DISTINCT", - "AS", - "EXISTS", - "ASC", - "DESC", - "INTO", - "DUPLICATE", - "KEY", - "DEFAULT", - "SET", - "LOCK", - "KEYS", - "VALUES", - "LAST_INSERT_ID", - "NEXT", - "VALUE", - "SHARE", - "MODE", - "SQL_NO_CACHE", - "SQL_CACHE", - "JOIN", - "STRAIGHT_JOIN", - "LEFT", - "RIGHT", - "INNER", - "OUTER", - "CROSS", - "NATURAL", - "USE", - "FORCE", - "ON", - "USING", - "'('", - "','", - "')'", - "ID", - "HEX", - "STRING", - "INTEGRAL", - "FLOAT", - "HEXNUM", - "VALUE_ARG", - "LIST_ARG", - "COMMENT", - "COMMENT_KEYWORD", - "BIT_LITERAL", - "NULL", - "TRUE", - "FALSE", - "OR", - "AND", - "NOT", - "'!'", - "BETWEEN", - "CASE", - "WHEN", - "THEN", - "ELSE", - "END", - "'='", - "'<'", - "'>'", - "LE", - "GE", - "NE", - "NULL_SAFE_EQUAL", - "IS", - "LIKE", - "REGEXP", - "IN", - "'|'", - "'&'", - "SHIFT_LEFT", - "SHIFT_RIGHT", - "'+'", - "'-'", - "'*'", - "'/'", - "DIV", - "'%'", - "MOD", - "'^'", - "'~'", - "UNARY", - "COLLATE", - "BINARY", - "UNDERSCORE_BINARY", - "INTERVAL", - "'.'", - "JSON_EXTRACT_OP", - "JSON_UNQUOTE_EXTRACT_OP", - "CREATE", - "ALTER", - "DROP", - "RENAME", - "ANALYZE", - "ADD", - "SCHEMA", - "TABLE", - "INDEX", - "VIEW", - "TO", - "IGNORE", - "IF", - "UNIQUE", - "PRIMARY", - "COLUMN", - "CONSTRAINT", - "SPATIAL", - "FULLTEXT", - "FOREIGN", - "KEY_BLOCK_SIZE", - "SHOW", - "DESCRIBE", - "EXPLAIN", - "DATE", - "ESCAPE", - "REPAIR", - "OPTIMIZE", - "TRUNCATE", - "MAXVALUE", - "PARTITION", - "REORGANIZE", - "LESS", - "THAN", - "PROCEDURE", - "TRIGGER", - "VINDEX", - "VINDEXES", - "STATUS", - "VARIABLES", - "BEGIN", - "START", - "TRANSACTION", - "COMMIT", - "ROLLBACK", - "BIT", - "TINYINT", - "SMALLINT", - "MEDIUMINT", - "INT", - "INTEGER", - "BIGINT", - "INTNUM", - "REAL", - "DOUBLE", - "FLOAT_TYPE", - "DECIMAL", - "NUMERIC", - "TIME", - "TIMESTAMP", - "DATETIME", - "YEAR", - "CHAR", - "VARCHAR", - "BOOL", - "CHARACTER", - "VARBINARY", - "NCHAR", - "TEXT", - "TINYTEXT", - "MEDIUMTEXT", - "LONGTEXT", - "BLOB", - "TINYBLOB", - "MEDIUMBLOB", - "LONGBLOB", - "JSON", - "ENUM", - "GEOMETRY", - "POINT", - "LINESTRING", - "POLYGON", - "GEOMETRYCOLLECTION", - "MULTIPOINT", - "MULTILINESTRING", - "MULTIPOLYGON", - "NULLX", - "AUTO_INCREMENT", - "APPROXNUM", - "SIGNED", - "UNSIGNED", - "ZEROFILL", - "DATABASES", - "TABLES", - "VITESS_KEYSPACES", - "VITESS_SHARDS", - "VITESS_TABLETS", - "VSCHEMA_TABLES", - "EXTENDED", - "FULL", - "PROCESSLIST", - "NAMES", - "CHARSET", - "GLOBAL", - "SESSION", - "ISOLATION", - "LEVEL", - "READ", - "WRITE", - "ONLY", - "REPEATABLE", - "COMMITTED", - "UNCOMMITTED", - "SERIALIZABLE", - "CURRENT_TIMESTAMP", - "DATABASE", - "CURRENT_DATE", - "CURRENT_TIME", - "LOCALTIME", - "LOCALTIMESTAMP", - "UTC_DATE", - "UTC_TIME", - "UTC_TIMESTAMP", - "REPLACE", - "CONVERT", - "CAST", - "SUBSTR", - "SUBSTRING", - "GROUP_CONCAT", - "SEPARATOR", - "MATCH", - "AGAINST", - "BOOLEAN", - "LANGUAGE", - "WITH", - "QUERY", - "EXPANSION", - "UNUSED", - "';'", -} -var yyStatenames = [...]string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyInitialStackSize = 16 - -//line yacctab:1 -var yyExca = [...]int{ - -1, 1, - 1, -1, - -2, 0, - -1, 3, - 5, 27, - -2, 4, - -1, 36, - 150, 263, - 151, 263, - -2, 253, - -1, 238, - 109, 587, - -2, 583, - -1, 239, - 109, 588, - -2, 584, - -1, 308, - 80, 746, - -2, 58, - -1, 309, - 80, 707, - -2, 59, - -1, 314, - 80, 691, - -2, 549, - -1, 316, - 80, 728, - -2, 551, - -1, 575, - 52, 41, - 54, 41, - -2, 43, - -1, 708, - 109, 590, - -2, 586, - -1, 912, - 5, 28, - -2, 395, - -1, 937, - 5, 27, - -2, 524, - -1, 1161, - 5, 28, - -2, 525, - -1, 1205, - 5, 27, - -2, 527, - -1, 1267, - 5, 28, - -2, 528, -} - -const yyPrivate = 57344 - -const yyLast = 10949 - -var yyAct = [...]int{ - - 269, 47, 770, 854, 1258, 522, 646, 1069, 1216, 1097, - 810, 1070, 268, 521, 3, 243, 1167, 834, 998, 788, - 806, 217, 569, 1066, 809, 53, 848, 771, 956, 1043, - 743, 567, 313, 904, 989, 945, 211, 410, 585, 710, - 455, 940, 733, 1001, 820, 740, 461, 584, 47, 844, - 307, 556, 571, 767, 294, 759, 222, 467, 475, 886, - 241, 216, 299, 226, 52, 304, 1287, 1277, 1285, 1265, - 302, 1283, 855, 442, 1276, 1061, 1155, 414, 435, 1225, - 212, 213, 214, 215, 295, 871, 1103, 1104, 1105, 1091, - 230, 1092, 1093, 293, 1108, 1106, 586, 1264, 587, 870, - 181, 177, 178, 179, 57, 536, 1240, 488, 487, 497, - 498, 490, 491, 492, 493, 494, 495, 496, 489, 964, - 801, 499, 963, 802, 803, 965, 875, 245, 450, 59, - 60, 61, 62, 63, 980, 869, 827, 310, 675, 1179, - 423, 437, 1194, 439, 835, 676, 1144, 1142, 210, 1284, - 232, 446, 447, 1282, 1259, 1022, 768, 424, 417, 1217, - 1044, 1223, 174, 175, 175, 822, 654, 239, 436, 438, - 420, 645, 1219, 822, 789, 791, 955, 954, 953, 412, - 189, 176, 1245, 866, 863, 864, 1164, 862, 1030, 298, - 1046, 511, 512, 974, 441, 441, 441, 441, 76, 441, - 920, 1019, 186, 898, 682, 186, 441, 1021, 479, 180, - 430, 1112, 873, 876, 489, 807, 822, 499, 499, 881, - 679, 1026, 1048, 47, 1052, 742, 1047, 472, 1045, 186, - 186, 76, 1009, 1050, 474, 186, 464, 76, 508, 1218, - 1250, 510, 1049, 474, 411, 1122, 463, 868, 790, 434, - 473, 472, 943, 588, 1107, 1051, 1053, 821, 1224, 1222, - 1007, 1113, 1241, 835, 828, 821, 1063, 474, 520, 867, - 524, 525, 526, 527, 528, 529, 530, 531, 532, 760, - 535, 537, 537, 537, 537, 537, 537, 537, 537, 545, - 546, 547, 548, 1263, 760, 649, 927, 1025, 882, 1020, - 568, 1018, 685, 686, 1253, 978, 872, 469, 821, 416, - 1009, 717, 236, 819, 817, 1269, 1185, 818, 1184, 874, - 426, 427, 428, 453, 1008, 715, 716, 714, 465, 1013, - 1010, 1003, 1004, 1011, 1006, 1005, 993, 50, 1007, 992, - 824, 916, 186, 915, 186, 825, 1012, 713, 473, 472, - 186, 981, 1015, 700, 702, 703, 917, 186, 701, 473, - 472, 76, 76, 76, 76, 474, 76, 173, 509, 458, - 462, 582, 576, 76, 1270, 1251, 474, 473, 472, 310, - 1201, 418, 419, 734, 1065, 735, 480, 538, 539, 540, - 541, 542, 543, 544, 474, 895, 896, 897, 1182, 1130, - 76, 990, 1008, 1248, 473, 472, 1100, 1013, 1010, 1003, - 1004, 1011, 1006, 1005, 441, 1273, 454, 1209, 1256, 454, - 523, 474, 441, 1099, 1012, 1209, 454, 298, 292, 534, - 1002, 1209, 1210, 441, 441, 441, 441, 441, 441, 441, - 441, 1176, 1175, 1088, 454, 1163, 454, 441, 441, 487, - 497, 498, 490, 491, 492, 493, 494, 495, 496, 489, - 186, 1229, 499, 663, 1119, 1118, 267, 186, 186, 186, - 1115, 1116, 1228, 76, 1115, 1114, 1151, 454, 1109, 76, - 910, 454, 50, 975, 966, 687, 857, 553, 454, 941, - 661, 745, 454, 21, 736, 711, 660, 74, 497, 498, - 490, 491, 492, 493, 494, 495, 496, 489, 659, 650, - 499, 47, 708, 488, 487, 497, 498, 490, 491, 492, - 493, 494, 495, 496, 489, 524, 648, 499, 643, 689, - 312, 595, 594, 942, 432, 704, 415, 425, 747, 706, - 411, 1067, 579, 681, 941, 752, 755, 54, 745, 221, - 23, 761, 1159, 707, 299, 299, 299, 299, 299, 513, - 514, 515, 516, 517, 518, 519, 23, 553, 772, 568, - 1121, 792, 737, 738, 935, 553, 942, 936, 299, 680, - 1117, 76, 747, 580, 967, 578, 910, 186, 186, 76, - 757, 186, 764, 1204, 186, 473, 472, 50, 186, 23, - 76, 76, 76, 76, 76, 76, 76, 76, 773, 796, - 712, 776, 474, 50, 76, 76, 785, 552, 941, 186, - 795, 1033, 578, 697, 698, 793, 836, 837, 838, 794, - 922, 799, 798, 814, 76, 800, 910, 919, 186, 774, - 775, 553, 777, 581, 76, 683, 50, 1189, 829, 441, - 849, 441, 1082, 223, 970, 310, 946, 947, 647, 441, - 312, 312, 312, 312, 910, 312, 845, 840, 811, 850, - 839, 65, 312, 921, 852, 523, 1102, 952, 750, 751, - 918, 298, 298, 298, 298, 298, 1067, 76, 994, 846, - 847, 558, 561, 562, 563, 559, 298, 560, 564, 477, - 50, 946, 947, 949, 657, 298, 451, 695, 899, 492, - 493, 494, 495, 496, 489, 708, 951, 499, 186, 779, - 778, 186, 186, 186, 186, 186, 782, 711, 888, 780, - 887, 783, 883, 186, 781, 784, 186, 562, 563, 805, - 186, 227, 228, 1281, 1275, 186, 186, 1029, 1280, 76, - 468, 748, 749, 893, 900, 892, 707, 756, 456, 1157, - 985, 593, 76, 433, 466, 977, 1255, 1190, 938, 939, - 457, 763, 312, 765, 766, 1254, 1202, 971, 590, 859, - 656, 937, 258, 257, 260, 261, 262, 263, 688, 566, - 468, 259, 264, 218, 709, 1234, 299, 718, 719, 720, - 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, - 731, 732, 950, 186, 926, 219, 76, 54, 76, 1233, - 968, 891, 186, 224, 225, 186, 76, 959, 1192, 890, - 942, 884, 885, 470, 462, 1242, 958, 1180, 960, 961, - 678, 56, 712, 58, 577, 744, 746, 51, 982, 983, - 1, 856, 997, 865, 441, 984, 1257, 986, 987, 988, - 1215, 762, 1096, 972, 973, 816, 808, 409, 830, 831, - 832, 833, 64, 1249, 815, 991, 1221, 1178, 823, 441, - 312, 979, 826, 811, 841, 842, 843, 1101, 312, 1252, - 976, 787, 600, 598, 599, 597, 911, 602, 1000, 312, - 312, 312, 312, 312, 312, 312, 312, 1014, 601, 596, - 197, 928, 305, 312, 312, 558, 561, 562, 563, 559, - 894, 560, 564, 298, 565, 589, 851, 471, 66, 999, - 1017, 1016, 861, 691, 1024, 1037, 674, 1072, 1068, 47, - 880, 1042, 449, 477, 199, 1036, 312, 1055, 507, 1071, - 1062, 772, 1073, 708, 1084, 1085, 1086, 772, 889, 1054, - 76, 962, 311, 186, 1074, 684, 1077, 909, 1076, 1078, - 460, 1232, 1035, 1191, 925, 533, 758, 76, 244, 699, - 1095, 256, 253, 924, 1089, 255, 739, 254, 690, 934, - 481, 242, 1094, 234, 1058, 297, 753, 753, 549, 557, - 555, 1090, 753, 1110, 1111, 490, 491, 492, 493, 494, - 495, 496, 489, 554, 948, 499, 944, 296, 1032, 753, - 76, 76, 1154, 76, 1239, 694, 25, 55, 901, 902, - 903, 229, 19, 18, 299, 17, 20, 16, 1123, 15, - 14, 811, 29, 811, 13, 12, 76, 11, 312, 186, - 186, 1125, 10, 9, 1128, 8, 7, 186, 6, 5, - 907, 312, 1153, 4, 908, 1133, 76, 220, 22, 2, - 0, 912, 913, 914, 1132, 1140, 0, 0, 1064, 0, - 923, 0, 0, 0, 0, 929, 0, 930, 931, 932, - 933, 0, 1158, 1079, 1080, 0, 0, 1081, 0, 1166, - 1083, 1169, 1170, 1171, 1035, 968, 76, 76, 0, 0, - 1172, 1174, 0, 0, 0, 312, 0, 312, 0, 0, - 0, 441, 0, 0, 0, 312, 0, 0, 0, 0, - 0, 0, 1181, 1188, 1183, 76, 0, 76, 76, 0, - 1187, 0, 0, 0, 0, 0, 0, 0, 0, 312, - 0, 0, 0, 0, 0, 0, 1193, 0, 0, 0, - 1072, 298, 186, 1206, 0, 0, 0, 0, 811, 0, - 76, 1203, 1071, 0, 0, 0, 1205, 1131, 0, 0, - 0, 0, 0, 76, 186, 0, 1220, 0, 0, 0, - 76, 1231, 1214, 0, 0, 999, 811, 0, 76, 0, - 0, 186, 1226, 0, 1227, 1072, 1230, 47, 0, 0, - 0, 0, 1243, 0, 0, 0, 1156, 1071, 1039, 1040, - 1244, 0, 0, 523, 1247, 0, 0, 0, 0, 0, - 0, 1056, 1057, 1041, 1059, 1060, 0, 0, 0, 459, - 1261, 0, 0, 0, 0, 1266, 0, 440, 0, 0, - 76, 0, 76, 76, 76, 186, 76, 0, 772, 957, - 0, 0, 76, 1271, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 1278, 312, 209, 1279, 0, - 1087, 0, 0, 0, 0, 1286, 0, 0, 76, 76, - 76, 0, 0, 300, 0, 0, 0, 0, 0, 233, - 0, 184, 184, 0, 0, 0, 0, 184, 0, 1137, - 1138, 0, 1139, 0, 0, 1141, 0, 1143, 0, 995, - 312, 0, 312, 0, 0, 0, 0, 0, 183, 0, - 0, 76, 76, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 76, 312, 0, 0, 0, 0, - 0, 1135, 0, 0, 0, 0, 303, 76, 0, 0, - 1134, 413, 0, 1177, 0, 312, 0, 1136, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 76, 1145, 1146, - 1147, 0, 0, 1150, 1260, 523, 0, 312, 0, 0, - 0, 0, 0, 0, 0, 0, 1160, 1161, 1162, 195, - 1165, 0, 753, 0, 0, 1075, 957, 0, 753, 0, - 0, 0, 0, 76, 184, 0, 184, 0, 0, 0, - 0, 0, 184, 205, 0, 0, 0, 76, 0, 184, - 0, 0, 0, 0, 312, 0, 312, 1098, 0, 0, - 0, 0, 443, 444, 445, 0, 448, 0, 0, 0, - 0, 0, 0, 452, 0, 0, 0, 0, 0, 0, - 0, 1195, 1196, 0, 1197, 1198, 1199, 0, 421, 1124, - 422, 0, 0, 190, 0, 0, 429, 0, 1200, 192, - 0, 0, 1126, 431, 0, 0, 198, 194, 0, 1129, - 0, 0, 0, 1211, 1212, 1213, 0, 312, 0, 0, - 488, 487, 497, 498, 490, 491, 492, 493, 494, 495, - 496, 489, 0, 196, 499, 0, 200, 0, 0, 1235, - 1236, 1237, 1238, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 184, 0, 0, 0, 0, 0, 0, 184, - 573, 184, 0, 0, 191, 0, 905, 0, 0, 1168, - 0, 1168, 1168, 1168, 0, 1173, 0, 0, 0, 0, - 0, 312, 0, 1262, 454, 0, 0, 0, 1267, 0, - 0, 193, 1152, 201, 202, 203, 204, 208, 1148, 454, - 0, 1272, 207, 206, 0, 0, 551, 312, 312, 312, - 0, 0, 0, 0, 0, 575, 0, 0, 0, 1288, - 488, 487, 497, 498, 490, 491, 492, 493, 494, 495, - 496, 489, 1290, 1291, 499, 488, 487, 497, 498, 490, - 491, 492, 493, 494, 495, 496, 489, 0, 0, 499, - 1207, 1208, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1098, 488, 487, 497, 498, 490, 491, - 492, 493, 494, 495, 496, 489, 1168, 0, 499, 184, - 184, 644, 0, 184, 0, 0, 184, 0, 0, 653, - 662, 0, 0, 0, 0, 0, 1246, 1038, 0, 0, - 664, 665, 666, 667, 668, 669, 670, 671, 0, 0, - 0, 184, 0, 0, 672, 673, 0, 488, 487, 497, - 498, 490, 491, 492, 493, 494, 495, 496, 489, 753, - 184, 499, 1268, 651, 652, 0, 0, 655, 0, 662, - 658, 0, 0, 0, 0, 0, 1274, 0, 0, 23, - 24, 48, 26, 27, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 677, 0, 1149, 42, 0, - 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, - 233, 0, 0, 0, 696, 233, 233, 0, 0, 754, - 754, 233, 37, 0, 0, 754, 50, 0, 0, 0, - 0, 0, 0, 0, 0, 233, 233, 233, 233, 0, - 184, 0, 754, 184, 184, 184, 184, 184, 0, 0, - 0, 0, 0, 0, 0, 786, 0, 0, 184, 0, - 0, 0, 573, 0, 0, 0, 0, 184, 184, 488, - 487, 497, 498, 490, 491, 492, 493, 494, 495, 496, - 489, 0, 0, 499, 0, 30, 31, 33, 32, 35, - 0, 0, 0, 0, 769, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 36, 43, 44, 0, - 0, 45, 46, 34, 0, 0, 0, 0, 0, 0, - 0, 0, 797, 0, 0, 38, 39, 0, 40, 41, - 0, 0, 0, 0, 0, 184, 617, 0, 0, 0, - 0, 483, 0, 486, 184, 0, 858, 184, 860, 500, - 501, 502, 503, 504, 505, 506, 879, 484, 485, 482, - 488, 487, 497, 498, 490, 491, 492, 493, 494, 495, - 496, 489, 662, 0, 499, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 233, 0, 0, 0, 0, 853, - 0, 0, 0, 906, 0, 0, 0, 0, 877, 0, - 0, 878, 0, 0, 0, 0, 0, 0, 49, 0, - 0, 0, 605, 488, 487, 497, 498, 490, 491, 492, - 493, 494, 495, 496, 489, 0, 0, 499, 0, 0, - 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 618, 0, 0, 0, 0, 233, 488, 487, - 497, 498, 490, 491, 492, 493, 494, 495, 496, 489, - 0, 0, 499, 631, 632, 633, 634, 635, 636, 637, - 0, 638, 639, 640, 641, 642, 619, 620, 621, 622, - 603, 604, 0, 0, 606, 184, 607, 608, 609, 610, - 611, 612, 613, 614, 615, 616, 623, 624, 625, 626, - 627, 628, 629, 630, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 996, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1027, 1028, 0, 0, 0, 1023, 0, 0, 184, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 662, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 754, 0, 0, 0, 0, - 0, 754, 0, 1031, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 184, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 184, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 184, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1120, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1127, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 573, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1186, 0, - 0, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 0, - 0, 0, 75, 0, 812, 813, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 969, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 0, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 754, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 398, 388, 0, 360, - 400, 338, 352, 408, 353, 354, 381, 324, 368, 125, - 350, 0, 341, 319, 347, 320, 339, 362, 93, 365, - 337, 390, 371, 107, 406, 109, 376, 0, 142, 118, - 0, 0, 364, 392, 366, 386, 359, 382, 329, 375, - 401, 351, 379, 402, 0, 0, 0, 75, 0, 812, - 813, 0, 0, 0, 0, 0, 86, 0, 378, 397, - 349, 380, 318, 377, 0, 322, 325, 407, 395, 344, - 345, 0, 0, 0, 0, 0, 0, 0, 363, 367, - 383, 357, 0, 0, 0, 0, 0, 0, 0, 0, - 342, 0, 374, 0, 0, 0, 326, 323, 0, 361, - 0, 0, 0, 328, 0, 343, 384, 0, 317, 387, - 393, 358, 187, 396, 356, 355, 399, 131, 0, 0, - 145, 98, 97, 106, 391, 340, 348, 89, 346, 137, - 127, 157, 373, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 84, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 321, 0, 143, 159, 172, 336, 394, 165, 166, 167, - 168, 0, 0, 0, 122, 85, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 332, 335, 330, - 331, 369, 370, 403, 404, 405, 385, 327, 0, 333, - 334, 0, 389, 372, 77, 0, 108, 169, 133, 95, - 160, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 50, - 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 0, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 0, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 398, 388, 0, 360, - 400, 338, 352, 408, 353, 354, 381, 324, 368, 125, - 350, 0, 341, 319, 347, 320, 339, 362, 93, 365, - 337, 390, 371, 107, 406, 109, 376, 0, 142, 118, - 0, 0, 364, 392, 366, 386, 359, 382, 329, 375, - 401, 351, 379, 402, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0, 0, 86, 0, 378, 397, - 349, 380, 318, 377, 0, 322, 325, 407, 395, 344, - 345, 0, 0, 0, 0, 0, 0, 0, 363, 367, - 383, 357, 0, 0, 0, 0, 0, 0, 1034, 0, - 342, 0, 374, 0, 0, 0, 326, 323, 0, 361, - 0, 0, 0, 328, 0, 343, 384, 0, 317, 387, - 393, 358, 187, 396, 356, 355, 399, 131, 0, 0, - 145, 98, 97, 106, 391, 340, 348, 89, 346, 137, - 127, 157, 373, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 84, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 321, 0, 143, 159, 172, 336, 394, 165, 166, 167, - 168, 0, 0, 0, 122, 85, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 332, 335, 330, - 331, 369, 370, 403, 404, 405, 385, 327, 0, 333, - 334, 0, 389, 372, 77, 0, 108, 169, 133, 95, - 160, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 0, - 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 705, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 0, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 398, 388, 0, 360, - 400, 338, 352, 408, 353, 354, 381, 324, 368, 125, - 350, 0, 341, 319, 347, 320, 339, 362, 93, 365, - 337, 390, 371, 107, 406, 109, 376, 0, 142, 118, - 0, 0, 364, 392, 366, 386, 359, 382, 329, 375, - 401, 351, 379, 402, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0, 0, 86, 0, 378, 397, - 349, 380, 318, 377, 0, 322, 325, 407, 395, 344, - 345, 0, 0, 0, 0, 0, 0, 0, 363, 367, - 383, 357, 0, 0, 0, 0, 0, 0, 0, 0, - 342, 0, 374, 0, 0, 0, 326, 323, 0, 361, - 0, 0, 0, 328, 0, 343, 384, 0, 317, 387, - 393, 358, 187, 396, 356, 355, 399, 131, 0, 0, - 145, 98, 97, 106, 391, 340, 348, 89, 346, 137, - 127, 157, 373, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 84, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 321, 0, 143, 159, 172, 336, 394, 165, 166, 167, - 168, 0, 0, 0, 122, 85, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 332, 335, 330, - 331, 369, 370, 403, 404, 405, 385, 327, 0, 333, - 334, 0, 389, 372, 77, 0, 108, 169, 133, 95, - 160, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 0, - 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 0, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 0, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 398, 388, 0, 360, - 400, 338, 352, 408, 353, 354, 381, 324, 368, 125, - 350, 0, 341, 319, 347, 320, 339, 362, 93, 365, - 337, 390, 371, 107, 406, 109, 376, 0, 142, 118, - 0, 0, 364, 392, 366, 386, 359, 382, 329, 375, - 401, 351, 379, 402, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0, 0, 86, 0, 378, 397, - 349, 380, 318, 377, 0, 322, 325, 407, 395, 344, - 345, 0, 0, 0, 0, 0, 0, 0, 363, 367, - 383, 357, 0, 0, 0, 0, 0, 0, 0, 0, - 342, 0, 374, 0, 0, 0, 326, 323, 0, 361, - 0, 0, 0, 328, 0, 343, 384, 0, 317, 387, - 393, 358, 187, 396, 356, 355, 399, 131, 0, 0, - 145, 98, 97, 106, 391, 340, 348, 89, 346, 137, - 127, 157, 373, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 315, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 321, 0, 143, 159, 172, 336, 394, 165, 166, 167, - 168, 0, 0, 0, 316, 314, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 332, 335, 330, - 331, 369, 370, 403, 404, 405, 385, 327, 0, 333, - 334, 0, 389, 372, 77, 0, 108, 169, 133, 95, - 160, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 0, - 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 0, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 0, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 398, 388, 0, 360, - 400, 338, 352, 408, 353, 354, 381, 324, 368, 125, - 350, 0, 341, 319, 347, 320, 339, 362, 93, 365, - 337, 390, 371, 107, 406, 109, 376, 0, 142, 118, - 0, 0, 364, 392, 366, 386, 359, 382, 329, 375, - 401, 351, 379, 402, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0, 0, 86, 0, 378, 397, - 349, 380, 318, 377, 0, 322, 325, 407, 395, 344, - 345, 0, 0, 0, 0, 0, 0, 0, 363, 367, - 383, 357, 0, 0, 0, 0, 0, 0, 0, 0, - 342, 0, 374, 0, 0, 0, 326, 323, 0, 361, - 0, 0, 0, 328, 0, 343, 384, 0, 317, 387, - 393, 358, 187, 396, 356, 355, 399, 131, 0, 0, - 145, 98, 97, 106, 391, 340, 348, 89, 346, 137, - 127, 157, 373, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 583, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 315, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 321, 0, 143, 159, 172, 336, 394, 165, 166, 167, - 168, 0, 0, 0, 316, 314, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 332, 335, 330, - 331, 369, 370, 403, 404, 405, 385, 327, 0, 333, - 334, 0, 389, 372, 77, 0, 108, 169, 133, 95, - 160, 398, 388, 0, 360, 400, 338, 352, 408, 353, - 354, 381, 324, 368, 125, 350, 0, 341, 319, 347, - 320, 339, 362, 93, 365, 337, 390, 371, 107, 406, - 109, 376, 0, 142, 118, 0, 0, 364, 392, 366, - 386, 359, 382, 329, 375, 401, 351, 379, 402, 0, - 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 378, 397, 349, 380, 318, 377, 0, - 322, 325, 407, 395, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 363, 367, 383, 357, 0, 0, 0, - 0, 0, 0, 0, 0, 342, 0, 374, 0, 0, - 0, 326, 323, 0, 361, 0, 0, 0, 328, 0, - 343, 384, 0, 317, 387, 393, 358, 187, 396, 356, - 355, 399, 131, 0, 0, 145, 98, 97, 106, 391, - 340, 348, 89, 346, 137, 127, 157, 373, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 306, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 315, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 321, 0, 143, 159, 172, - 336, 394, 165, 166, 167, 168, 0, 0, 0, 316, - 314, 309, 308, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 332, 335, 330, 331, 369, 370, 403, 404, - 405, 385, 327, 0, 333, 334, 0, 389, 372, 77, - 0, 108, 169, 133, 95, 160, 125, 0, 0, 741, - 0, 240, 0, 0, 0, 93, 0, 237, 0, 0, - 107, 279, 109, 0, 0, 142, 118, 0, 0, 0, - 0, 270, 271, 0, 0, 0, 0, 0, 0, 0, - 0, 50, 0, 0, 238, 258, 257, 260, 261, 262, - 263, 0, 0, 86, 259, 264, 265, 266, 0, 0, - 235, 251, 0, 278, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 248, 249, 231, 0, 0, 0, 290, - 0, 250, 0, 0, 246, 247, 252, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, - 0, 0, 288, 0, 131, 0, 0, 145, 98, 97, - 106, 0, 0, 0, 89, 0, 137, 127, 157, 0, - 128, 136, 110, 149, 132, 156, 188, 164, 147, 163, - 78, 146, 155, 87, 139, 80, 153, 144, 116, 102, - 103, 79, 0, 135, 92, 96, 91, 124, 150, 151, - 90, 171, 83, 162, 82, 84, 161, 123, 148, 154, - 117, 114, 81, 152, 115, 113, 105, 94, 99, 129, - 112, 130, 100, 120, 119, 121, 0, 0, 0, 143, - 159, 172, 0, 0, 165, 166, 167, 168, 0, 0, - 0, 122, 85, 101, 140, 104, 111, 134, 170, 126, - 138, 88, 158, 141, 280, 289, 286, 287, 284, 285, - 283, 282, 281, 291, 272, 273, 274, 275, 277, 0, - 276, 77, 0, 108, 169, 133, 95, 160, 125, 0, - 0, 0, 0, 240, 0, 0, 0, 93, 0, 237, - 0, 0, 107, 279, 109, 0, 0, 142, 118, 0, - 0, 0, 0, 270, 271, 0, 0, 0, 0, 0, - 0, 0, 0, 50, 0, 454, 238, 258, 257, 260, - 261, 262, 263, 0, 0, 86, 259, 264, 265, 266, - 0, 0, 235, 251, 0, 278, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 248, 249, 0, 0, 0, - 0, 290, 0, 250, 0, 0, 246, 247, 252, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 0, 0, 288, 0, 131, 0, 0, 145, - 98, 97, 106, 0, 0, 0, 89, 0, 137, 127, - 157, 0, 128, 136, 110, 149, 132, 156, 188, 164, - 147, 163, 78, 146, 155, 87, 139, 80, 153, 144, - 116, 102, 103, 79, 0, 135, 92, 96, 91, 124, - 150, 151, 90, 171, 83, 162, 82, 84, 161, 123, - 148, 154, 117, 114, 81, 152, 115, 113, 105, 94, - 99, 129, 112, 130, 100, 120, 119, 121, 0, 0, - 0, 143, 159, 172, 0, 0, 165, 166, 167, 168, - 0, 0, 0, 122, 85, 101, 140, 104, 111, 134, - 170, 126, 138, 88, 158, 141, 280, 289, 286, 287, - 284, 285, 283, 282, 281, 291, 272, 273, 274, 275, - 277, 0, 276, 77, 0, 108, 169, 133, 95, 160, - 125, 0, 0, 0, 0, 240, 0, 0, 0, 93, - 0, 237, 0, 0, 107, 279, 109, 0, 0, 142, - 118, 0, 0, 0, 0, 270, 271, 0, 0, 0, - 0, 0, 0, 0, 0, 50, 0, 0, 238, 258, - 257, 260, 261, 262, 263, 0, 0, 86, 259, 264, - 265, 266, 0, 0, 235, 251, 0, 278, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 248, 249, 231, - 0, 0, 0, 290, 0, 250, 0, 0, 246, 247, - 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 0, 0, 288, 0, 131, 0, - 0, 145, 98, 97, 106, 0, 0, 0, 89, 0, - 137, 127, 157, 0, 128, 136, 110, 149, 132, 156, - 188, 164, 147, 163, 78, 146, 155, 87, 139, 80, - 153, 144, 116, 102, 103, 79, 0, 135, 92, 96, - 91, 124, 150, 151, 90, 171, 83, 162, 82, 84, - 161, 123, 148, 154, 117, 114, 81, 152, 115, 113, - 105, 94, 99, 129, 112, 130, 100, 120, 119, 121, - 0, 0, 0, 143, 159, 172, 0, 0, 165, 166, - 167, 168, 0, 0, 0, 122, 85, 101, 140, 104, - 111, 134, 170, 126, 138, 88, 158, 141, 280, 289, - 286, 287, 284, 285, 283, 282, 281, 291, 272, 273, - 274, 275, 277, 0, 276, 77, 0, 108, 169, 133, - 95, 160, 125, 0, 0, 0, 0, 240, 0, 0, - 0, 93, 0, 237, 0, 0, 107, 279, 109, 0, - 0, 142, 118, 0, 0, 0, 0, 270, 271, 0, - 0, 0, 0, 0, 0, 804, 0, 50, 0, 0, - 238, 258, 257, 260, 261, 262, 263, 0, 0, 86, - 259, 264, 265, 266, 0, 0, 235, 251, 0, 278, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, - 249, 0, 0, 0, 0, 290, 0, 250, 0, 0, - 246, 247, 252, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 0, 0, 288, 0, - 131, 0, 0, 145, 98, 97, 106, 0, 0, 0, - 89, 0, 137, 127, 157, 0, 128, 136, 110, 149, - 132, 156, 188, 164, 147, 163, 78, 146, 155, 87, - 139, 80, 153, 144, 116, 102, 103, 79, 0, 135, - 92, 96, 91, 124, 150, 151, 90, 171, 83, 162, - 82, 84, 161, 123, 148, 154, 117, 114, 81, 152, - 115, 113, 105, 94, 99, 129, 112, 130, 100, 120, - 119, 121, 0, 0, 0, 143, 159, 172, 0, 0, - 165, 166, 167, 168, 0, 0, 0, 122, 85, 101, - 140, 104, 111, 134, 170, 126, 138, 88, 158, 141, - 280, 289, 286, 287, 284, 285, 283, 282, 281, 291, - 272, 273, 274, 275, 277, 23, 276, 77, 0, 108, - 169, 133, 95, 160, 0, 0, 0, 125, 0, 0, - 0, 0, 240, 0, 0, 0, 93, 0, 237, 0, - 0, 107, 279, 109, 0, 0, 142, 118, 0, 0, - 0, 0, 270, 271, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 0, 0, 238, 258, 257, 260, 261, - 262, 263, 0, 0, 86, 259, 264, 265, 266, 0, - 0, 235, 251, 0, 278, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 248, 249, 0, 0, 0, 0, - 290, 0, 250, 0, 0, 246, 247, 252, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 0, 0, 288, 0, 131, 0, 0, 145, 98, - 97, 106, 0, 0, 0, 89, 0, 137, 127, 157, - 0, 128, 136, 110, 149, 132, 156, 188, 164, 147, - 163, 78, 146, 155, 87, 139, 80, 153, 144, 116, - 102, 103, 79, 0, 135, 92, 96, 91, 124, 150, - 151, 90, 171, 83, 162, 82, 84, 161, 123, 148, - 154, 117, 114, 81, 152, 115, 113, 105, 94, 99, - 129, 112, 130, 100, 120, 119, 121, 0, 0, 0, - 143, 159, 172, 0, 0, 165, 166, 167, 168, 0, - 0, 0, 122, 85, 101, 140, 104, 111, 134, 170, - 126, 138, 88, 158, 141, 280, 289, 286, 287, 284, - 285, 283, 282, 281, 291, 272, 273, 274, 275, 277, - 0, 276, 77, 0, 108, 169, 133, 95, 160, 125, - 0, 0, 0, 0, 240, 0, 0, 0, 93, 0, - 237, 0, 0, 107, 279, 109, 0, 0, 142, 118, - 0, 0, 0, 0, 270, 271, 0, 0, 0, 0, - 0, 0, 0, 0, 50, 0, 0, 238, 258, 257, - 260, 261, 262, 263, 0, 0, 86, 259, 264, 265, - 266, 0, 0, 235, 251, 0, 278, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 248, 249, 0, 0, - 0, 0, 290, 0, 250, 0, 0, 246, 247, 252, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 0, 0, 288, 0, 131, 0, 0, - 145, 98, 97, 106, 0, 0, 0, 89, 0, 137, - 127, 157, 0, 128, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 84, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 0, 0, 143, 159, 172, 0, 0, 165, 166, 167, - 168, 0, 0, 0, 122, 85, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 280, 289, 286, - 287, 284, 285, 283, 282, 281, 291, 272, 273, 274, - 275, 277, 125, 276, 77, 0, 108, 169, 133, 95, - 160, 93, 0, 0, 0, 0, 107, 279, 109, 0, - 0, 142, 118, 0, 0, 0, 0, 270, 271, 0, - 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, - 238, 258, 257, 260, 261, 262, 263, 0, 0, 86, - 259, 264, 265, 266, 0, 0, 0, 251, 0, 278, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, - 249, 0, 0, 0, 0, 290, 0, 250, 0, 0, - 246, 247, 252, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 0, 0, 288, 0, - 131, 0, 0, 145, 98, 97, 106, 0, 0, 0, - 89, 0, 137, 127, 157, 1289, 128, 136, 110, 149, - 132, 156, 188, 164, 147, 163, 78, 146, 155, 87, - 139, 80, 153, 144, 116, 102, 103, 79, 0, 135, - 92, 96, 91, 124, 150, 151, 90, 171, 83, 162, - 82, 84, 161, 123, 148, 154, 117, 114, 81, 152, - 115, 113, 105, 94, 99, 129, 112, 130, 100, 120, - 119, 121, 0, 0, 0, 143, 159, 172, 0, 0, - 165, 166, 167, 168, 0, 0, 0, 122, 85, 101, - 140, 104, 111, 134, 170, 126, 138, 88, 158, 141, - 280, 289, 286, 287, 284, 285, 283, 282, 281, 291, - 272, 273, 274, 275, 277, 125, 276, 77, 0, 108, - 169, 133, 95, 160, 93, 0, 0, 0, 0, 107, - 279, 109, 0, 0, 142, 118, 0, 0, 0, 0, - 270, 271, 0, 0, 0, 0, 0, 0, 0, 0, - 50, 0, 0, 238, 258, 257, 260, 261, 262, 263, - 0, 0, 86, 259, 264, 265, 266, 0, 0, 0, - 251, 0, 278, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 248, 249, 0, 0, 0, 0, 290, 0, - 250, 0, 0, 246, 247, 252, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 0, - 0, 288, 0, 131, 0, 0, 145, 98, 97, 106, - 0, 0, 0, 89, 0, 137, 127, 157, 0, 128, - 136, 110, 149, 132, 156, 188, 164, 147, 163, 78, - 146, 155, 87, 139, 80, 153, 144, 116, 102, 103, - 79, 0, 135, 92, 96, 91, 124, 150, 151, 90, - 171, 83, 162, 82, 84, 161, 123, 148, 154, 117, - 114, 81, 152, 115, 113, 105, 94, 99, 129, 112, - 130, 100, 120, 119, 121, 0, 0, 0, 143, 159, - 172, 0, 0, 165, 166, 167, 168, 0, 0, 0, - 122, 85, 101, 140, 104, 111, 134, 170, 126, 138, - 88, 158, 141, 280, 289, 286, 287, 284, 285, 283, - 282, 281, 291, 272, 273, 274, 275, 277, 125, 276, - 77, 0, 108, 169, 133, 95, 160, 93, 0, 0, - 0, 0, 107, 0, 109, 0, 0, 142, 118, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, - 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 488, 487, 497, 498, 490, 491, 492, 493, 494, - 495, 496, 489, 0, 0, 499, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 0, 0, 0, 0, 131, 0, 0, 145, - 98, 97, 106, 0, 0, 0, 89, 0, 137, 127, - 157, 0, 128, 136, 110, 149, 132, 156, 188, 164, - 147, 163, 78, 146, 155, 87, 139, 80, 153, 144, - 116, 102, 103, 79, 0, 135, 92, 96, 91, 124, - 150, 151, 90, 171, 83, 162, 82, 84, 161, 123, - 148, 154, 117, 114, 81, 152, 115, 113, 105, 94, - 99, 129, 112, 130, 100, 120, 119, 121, 0, 0, - 0, 143, 159, 172, 0, 0, 165, 166, 167, 168, - 0, 0, 0, 122, 85, 101, 140, 104, 111, 134, - 170, 126, 138, 88, 158, 141, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 77, 0, 108, 169, 133, 95, 160, - 125, 0, 0, 0, 476, 0, 0, 0, 0, 93, - 0, 0, 0, 0, 107, 0, 109, 0, 0, 142, - 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, - 478, 0, 0, 0, 0, 0, 0, 86, 0, 0, - 0, 0, 473, 472, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 474, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 187, 0, 0, 0, 0, 131, 0, - 0, 145, 98, 97, 106, 0, 0, 0, 89, 0, - 137, 127, 157, 0, 128, 136, 110, 149, 132, 156, - 188, 164, 147, 163, 78, 146, 155, 87, 139, 80, - 153, 144, 116, 102, 103, 79, 0, 135, 92, 96, - 91, 124, 150, 151, 90, 171, 83, 162, 82, 84, - 161, 123, 148, 154, 117, 114, 81, 152, 115, 113, - 105, 94, 99, 129, 112, 130, 100, 120, 119, 121, - 0, 0, 0, 143, 159, 172, 0, 0, 165, 166, - 167, 168, 0, 0, 0, 122, 85, 101, 140, 104, - 111, 134, 170, 126, 138, 88, 158, 141, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 125, 0, 77, 0, 108, 169, 133, - 95, 160, 93, 0, 0, 0, 0, 107, 0, 109, - 0, 0, 142, 118, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, - 86, 0, 0, 0, 0, 68, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 71, 72, 0, 67, 0, 0, 0, - 73, 131, 0, 0, 145, 98, 97, 106, 0, 0, - 0, 89, 0, 137, 127, 157, 0, 128, 136, 110, - 149, 132, 156, 69, 164, 147, 163, 78, 146, 155, - 87, 139, 80, 153, 144, 116, 102, 103, 79, 0, - 135, 92, 96, 91, 124, 150, 151, 90, 171, 83, - 162, 82, 84, 161, 123, 148, 154, 117, 114, 81, - 152, 115, 113, 105, 94, 99, 129, 112, 130, 100, - 120, 119, 121, 0, 0, 0, 143, 159, 172, 0, - 0, 165, 166, 167, 168, 0, 0, 0, 122, 85, - 101, 140, 104, 111, 134, 170, 126, 138, 88, 158, - 141, 0, 70, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, - 108, 169, 133, 95, 160, 125, 0, 0, 0, 572, - 0, 0, 0, 0, 93, 0, 0, 0, 0, 107, - 0, 109, 0, 0, 142, 118, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 0, 574, 0, 0, 0, 0, - 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 0, - 0, 0, 0, 131, 0, 0, 145, 98, 97, 106, - 0, 0, 0, 89, 0, 137, 127, 157, 0, 128, - 136, 110, 149, 132, 156, 188, 164, 147, 163, 78, - 146, 155, 87, 139, 80, 153, 144, 116, 102, 103, - 79, 0, 135, 92, 96, 91, 124, 150, 151, 90, - 171, 83, 162, 82, 84, 161, 123, 148, 154, 117, - 114, 81, 152, 115, 113, 105, 94, 99, 129, 112, - 130, 100, 120, 119, 121, 0, 0, 0, 143, 159, - 172, 0, 0, 165, 166, 167, 168, 0, 0, 0, - 122, 85, 101, 140, 104, 111, 134, 170, 126, 138, - 88, 158, 141, 0, 0, 0, 23, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, - 77, 0, 108, 169, 133, 95, 160, 93, 0, 0, - 0, 0, 107, 0, 109, 0, 0, 142, 118, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 50, 0, 0, 75, 0, 0, 0, - 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 0, 0, 0, 0, 131, 0, 0, 145, - 98, 97, 106, 0, 0, 0, 89, 0, 137, 127, - 157, 0, 128, 136, 110, 149, 132, 156, 188, 164, - 147, 163, 78, 146, 155, 87, 139, 80, 153, 144, - 116, 102, 103, 79, 0, 135, 92, 96, 91, 124, - 150, 151, 90, 171, 83, 162, 82, 84, 161, 123, - 148, 154, 117, 114, 81, 152, 115, 113, 105, 94, - 99, 129, 112, 130, 100, 120, 119, 121, 0, 0, - 0, 143, 159, 172, 0, 0, 165, 166, 167, 168, - 0, 0, 0, 122, 85, 101, 140, 104, 111, 134, - 170, 126, 138, 88, 158, 141, 0, 0, 0, 23, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 125, 0, 77, 0, 108, 169, 133, 95, 160, - 93, 0, 0, 0, 0, 107, 0, 109, 0, 0, - 142, 118, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 50, 0, 0, 185, - 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 187, 0, 0, 0, 0, 131, - 0, 0, 145, 98, 97, 106, 0, 0, 0, 89, - 0, 137, 127, 157, 0, 128, 136, 110, 149, 132, - 156, 188, 164, 147, 163, 78, 146, 155, 87, 139, - 80, 153, 144, 116, 102, 103, 79, 0, 135, 92, - 96, 91, 124, 150, 151, 90, 171, 83, 162, 82, - 84, 161, 123, 148, 154, 117, 114, 81, 152, 115, - 113, 105, 94, 99, 129, 112, 130, 100, 120, 119, - 121, 0, 0, 0, 143, 159, 172, 0, 0, 165, - 166, 167, 168, 0, 0, 0, 122, 85, 101, 140, - 104, 111, 134, 170, 126, 138, 88, 158, 141, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 125, 0, 77, 0, 108, 169, - 133, 95, 160, 93, 0, 0, 0, 0, 107, 0, - 109, 0, 0, 142, 118, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 75, 0, 0, 692, 0, 0, 693, 0, - 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, - 0, 0, 131, 0, 0, 145, 98, 97, 106, 0, - 0, 0, 89, 0, 137, 127, 157, 0, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 0, 0, 143, 159, 172, - 0, 0, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 125, 0, 77, - 0, 108, 169, 133, 95, 160, 93, 0, 592, 0, - 0, 107, 0, 109, 0, 0, 142, 118, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 0, 591, 0, 0, - 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 0, 0, 0, 0, 131, 0, 0, 145, 98, - 97, 106, 0, 0, 0, 89, 0, 137, 127, 157, - 0, 128, 136, 110, 149, 132, 156, 188, 164, 147, - 163, 78, 146, 155, 87, 139, 80, 153, 144, 116, - 102, 103, 79, 0, 135, 92, 96, 91, 124, 150, - 151, 90, 171, 83, 162, 82, 84, 161, 123, 148, - 154, 117, 114, 81, 152, 115, 113, 105, 94, 99, - 129, 112, 130, 100, 120, 119, 121, 0, 0, 0, - 143, 159, 172, 0, 0, 165, 166, 167, 168, 0, - 0, 0, 122, 85, 101, 140, 104, 111, 134, 170, - 126, 138, 88, 158, 141, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 77, 0, 108, 169, 133, 95, 160, 125, - 0, 0, 0, 572, 0, 0, 0, 0, 93, 0, - 0, 0, 0, 107, 0, 109, 0, 0, 142, 118, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 185, 0, 574, - 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 187, 0, 0, 0, 0, 131, 0, 0, - 145, 98, 97, 106, 0, 0, 0, 89, 0, 137, - 127, 157, 0, 570, 136, 110, 149, 132, 156, 188, - 164, 147, 163, 78, 146, 155, 87, 139, 80, 153, - 144, 116, 102, 103, 79, 0, 135, 92, 96, 91, - 124, 150, 151, 90, 171, 83, 162, 82, 84, 161, - 123, 148, 154, 117, 114, 81, 152, 115, 113, 105, - 94, 99, 129, 112, 130, 100, 120, 119, 121, 0, - 0, 0, 143, 159, 172, 0, 0, 165, 166, 167, - 168, 0, 0, 0, 122, 85, 101, 140, 104, 111, - 134, 170, 126, 138, 88, 158, 141, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 125, 0, 77, 0, 108, 169, 133, 95, - 160, 93, 0, 0, 0, 0, 107, 0, 109, 0, - 0, 142, 118, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, - 185, 0, 0, 0, 0, 0, 0, 0, 0, 86, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, - 131, 0, 0, 145, 98, 97, 106, 0, 0, 0, - 89, 0, 137, 127, 157, 0, 128, 136, 110, 149, - 132, 156, 188, 164, 147, 163, 78, 146, 155, 87, - 139, 80, 153, 144, 116, 102, 103, 79, 0, 135, - 92, 96, 91, 124, 150, 151, 90, 171, 83, 162, - 82, 84, 161, 123, 148, 154, 117, 114, 81, 152, - 115, 113, 105, 94, 99, 129, 112, 130, 100, 120, - 119, 121, 0, 0, 0, 143, 159, 172, 0, 0, - 165, 166, 167, 168, 0, 0, 0, 122, 85, 101, - 140, 104, 111, 134, 170, 126, 138, 88, 158, 141, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 125, 0, 77, 0, 108, - 169, 133, 95, 160, 93, 0, 0, 0, 0, 107, - 0, 109, 0, 0, 142, 118, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 0, 574, 0, 0, 0, 0, - 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 0, - 0, 0, 0, 131, 0, 0, 145, 98, 97, 106, - 0, 0, 0, 89, 0, 137, 127, 157, 0, 128, - 136, 110, 149, 132, 156, 188, 164, 147, 163, 78, - 146, 155, 87, 139, 80, 153, 144, 116, 102, 103, - 79, 0, 135, 92, 96, 91, 124, 150, 151, 90, - 171, 83, 162, 82, 84, 161, 123, 148, 154, 117, - 114, 81, 152, 115, 113, 105, 94, 99, 129, 112, - 130, 100, 120, 119, 121, 0, 0, 0, 143, 159, - 172, 0, 0, 165, 166, 167, 168, 0, 0, 0, - 122, 85, 101, 140, 104, 111, 134, 170, 126, 138, - 88, 158, 141, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, - 77, 0, 108, 169, 133, 95, 160, 93, 0, 0, - 0, 0, 107, 0, 109, 0, 0, 142, 118, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 75, 0, 478, 0, - 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 187, 0, 0, 0, 0, 131, 0, 0, 145, - 98, 97, 106, 0, 0, 0, 89, 0, 137, 127, - 157, 0, 128, 136, 110, 149, 132, 156, 188, 164, - 147, 163, 78, 146, 155, 87, 139, 80, 153, 144, - 116, 102, 103, 79, 0, 135, 92, 96, 91, 124, - 150, 151, 90, 171, 83, 162, 82, 84, 161, 123, - 148, 154, 117, 114, 81, 152, 115, 113, 105, 94, - 99, 129, 112, 130, 100, 120, 119, 121, 0, 0, - 0, 143, 159, 172, 0, 0, 165, 166, 167, 168, - 0, 0, 0, 122, 85, 101, 140, 104, 111, 134, - 170, 126, 138, 88, 158, 141, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 125, 77, 0, 108, 169, 133, 95, 160, - 550, 93, 0, 0, 0, 0, 107, 0, 109, 0, - 0, 142, 118, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 185, 0, 0, 0, 0, 0, 0, 0, 0, 86, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, - 131, 0, 0, 145, 98, 97, 106, 0, 0, 0, - 89, 0, 137, 127, 157, 0, 128, 136, 110, 149, - 132, 156, 188, 164, 147, 163, 78, 146, 155, 87, - 139, 80, 153, 144, 116, 102, 103, 79, 0, 135, - 92, 96, 91, 124, 150, 151, 90, 171, 83, 162, - 82, 84, 161, 123, 148, 154, 117, 114, 81, 152, - 115, 113, 105, 94, 99, 129, 112, 130, 100, 120, - 119, 121, 0, 0, 0, 143, 159, 172, 0, 0, - 165, 166, 167, 168, 0, 0, 0, 122, 85, 101, - 140, 104, 111, 134, 170, 126, 138, 88, 158, 141, - 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, - 0, 0, 0, 0, 0, 125, 0, 77, 0, 108, - 169, 133, 95, 160, 93, 0, 0, 0, 0, 107, - 0, 109, 0, 0, 142, 118, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, - 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 187, 0, - 0, 0, 0, 131, 0, 0, 145, 98, 97, 106, - 0, 0, 0, 89, 0, 137, 127, 157, 0, 128, - 136, 110, 149, 132, 156, 188, 164, 147, 163, 78, - 146, 155, 87, 139, 80, 153, 144, 116, 102, 103, - 79, 0, 135, 92, 96, 91, 124, 150, 151, 90, - 171, 83, 162, 82, 84, 161, 123, 148, 154, 117, - 114, 81, 152, 115, 113, 105, 94, 99, 129, 112, - 130, 100, 120, 119, 121, 0, 0, 0, 143, 159, - 172, 0, 0, 165, 166, 167, 168, 0, 0, 0, - 122, 85, 101, 140, 104, 111, 134, 170, 126, 138, - 88, 158, 141, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, - 77, 0, 108, 169, 133, 95, 160, 93, 0, 0, - 0, 0, 107, 0, 109, 0, 0, 142, 118, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, - 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, - 0, 187, 0, 0, 0, 0, 131, 0, 0, 145, - 98, 97, 106, 0, 0, 0, 89, 0, 137, 127, - 157, 0, 128, 136, 110, 149, 132, 156, 188, 164, - 147, 163, 78, 146, 155, 87, 139, 80, 153, 144, - 116, 102, 103, 79, 0, 135, 92, 96, 91, 124, - 150, 151, 90, 171, 83, 162, 82, 84, 161, 123, - 148, 154, 117, 114, 81, 152, 115, 113, 105, 94, - 99, 129, 112, 130, 100, 120, 119, 121, 0, 0, - 0, 143, 159, 172, 0, 0, 165, 166, 167, 168, - 0, 0, 0, 122, 85, 101, 140, 104, 111, 134, - 170, 126, 138, 88, 158, 141, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 125, 0, 77, 0, 108, 169, 133, 95, 160, - 93, 0, 0, 0, 0, 107, 0, 109, 0, 0, - 142, 118, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, - 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 187, 0, 0, 0, 0, 131, - 0, 0, 145, 98, 97, 106, 0, 0, 0, 89, - 0, 137, 127, 157, 0, 128, 136, 110, 149, 132, - 156, 188, 164, 147, 163, 78, 146, 155, 87, 139, - 80, 153, 144, 116, 102, 103, 79, 0, 135, 92, - 96, 91, 124, 150, 151, 90, 171, 83, 162, 82, - 84, 161, 123, 148, 154, 117, 114, 81, 152, 115, - 113, 105, 94, 99, 129, 112, 130, 100, 120, 119, - 121, 0, 0, 0, 143, 159, 172, 0, 0, 165, - 166, 167, 168, 0, 0, 0, 122, 85, 101, 140, - 104, 111, 134, 170, 126, 138, 88, 158, 141, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 125, 0, 77, 0, 108, 169, - 133, 95, 160, 93, 0, 0, 0, 0, 107, 0, - 109, 0, 0, 142, 118, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, - 0, 0, 131, 0, 0, 145, 98, 97, 106, 0, - 0, 0, 89, 0, 137, 127, 157, 0, 128, 136, - 110, 149, 132, 156, 188, 164, 147, 163, 78, 146, - 155, 87, 139, 80, 153, 144, 116, 102, 103, 79, - 0, 135, 92, 96, 91, 124, 150, 151, 90, 171, - 83, 162, 82, 84, 161, 123, 148, 154, 117, 114, - 81, 152, 115, 113, 105, 94, 99, 129, 112, 130, - 100, 120, 119, 121, 0, 0, 0, 143, 159, 172, - 0, 0, 165, 166, 167, 168, 0, 0, 0, 122, - 85, 101, 140, 104, 111, 134, 170, 126, 138, 88, - 158, 141, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 125, 0, 77, - 0, 108, 169, 133, 95, 160, 93, 0, 0, 0, - 0, 107, 0, 109, 0, 0, 142, 118, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, - 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 187, 0, 0, 0, 0, 131, 0, 0, 145, 98, - 97, 106, 0, 0, 0, 89, 0, 137, 127, 157, - 0, 128, 136, 110, 149, 132, 156, 188, 164, 147, - 163, 78, 146, 155, 87, 139, 80, 153, 144, 116, - 102, 103, 79, 0, 135, 92, 96, 91, 124, 150, - 151, 90, 171, 83, 162, 82, 84, 161, 123, 148, - 154, 117, 114, 81, 152, 115, 113, 105, 94, 99, - 129, 112, 130, 100, 120, 119, 121, 0, 0, 0, - 143, 159, 172, 0, 0, 165, 166, 167, 168, 0, - 0, 0, 122, 85, 101, 140, 104, 111, 134, 170, - 126, 138, 88, 158, 141, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 77, 0, 108, 169, 133, 95, 160, -} -var yyPact = [...]int{ - - 1723, -1000, -186, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 802, 836, -1000, -1000, -1000, -1000, -1000, -1000, 618, - 7335, 41, 62, -18, 10030, 61, 1367, 10699, -1000, -6, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 593, -1000, -1000, - -1000, -1000, -1000, 776, 799, 647, 803, 702, -1000, 5512, - 40, 8914, 9807, 4816, -1000, 484, 59, 10699, -158, 10253, - 34, 34, 34, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 51, 10699, -1000, 10699, 33, 481, 33, - 33, 33, 10699, -1000, 101, -1000, -1000, -1000, -1000, 10699, - 478, 733, 22, 2856, 2856, 2856, 2856, 1, 2856, -83, - 655, -1000, -1000, -1000, -1000, 2856, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 364, 739, 6211, 6211, - 802, -1000, 593, -1000, -1000, -1000, 729, -1000, -1000, 243, - 822, -1000, 7112, 99, -1000, 6211, 1819, 429, -1000, -1000, - 429, -1000, -1000, 81, -1000, -1000, 6657, 6657, 6657, 6657, - 6657, 6657, 6657, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 429, -1000, 5979, - 429, 429, 429, 429, 429, 429, 429, 429, 6211, 429, - 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, - 429, 429, 9584, 587, 874, -1000, -1000, -1000, 767, 8013, - 8691, 10699, 531, -1000, 589, 4571, -121, -1000, -1000, -1000, - 173, 8459, -1000, -1000, -1000, 731, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 477, - -1000, 1856, 472, 2856, 50, 606, 470, 223, 453, 10699, - 10699, 2856, 44, 10699, 757, 653, 10699, 452, 440, -1000, - 4326, -1000, 2856, 2856, 2856, 2856, 2856, 2856, 2856, 2856, - -1000, -1000, -1000, -1000, -1000, -1000, 2856, 2856, -1000, -67, - -1000, 10699, -1000, -1000, -1000, -1000, 831, 130, 525, 95, - 591, -1000, 278, 776, 364, 702, 8236, 665, -1000, -1000, - 10699, -1000, 6211, 6211, 286, -1000, 9360, -1000, -1000, 3346, - 147, 6657, 284, 237, 6657, 6657, 6657, 6657, 6657, 6657, - 6657, 6657, 6657, 6657, 6657, 6657, 6657, 6657, 6657, 327, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 438, -1000, - 593, 725, 725, 113, 113, 113, 113, 113, 113, 6880, - 5048, 364, 437, 180, 5979, 5512, 5512, 6211, 6211, 10476, - 10476, 5512, 769, 203, 180, 10476, -1000, 364, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 5512, 5512, 5512, 5512, 14, - 10699, -1000, 10476, 8914, 8914, 8914, 8914, 8914, -1000, 679, - 678, -1000, 688, 685, 694, 10699, -1000, 433, 8013, 125, - 429, -1000, 9137, -1000, -1000, 14, 568, 8914, 10699, -1000, - -1000, 4081, 589, -121, 581, -1000, -98, -97, 5744, 110, - -1000, -1000, -1000, -1000, 2611, 188, 273, -66, -1000, -1000, - -1000, 595, -1000, 595, 595, 595, 595, -33, -33, -33, - -33, -1000, -1000, -1000, -1000, -1000, 617, 614, -1000, 595, - 595, 595, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 613, 613, - 613, 597, 597, 622, -1000, 10699, -174, 430, 2856, 756, - 2856, -1000, 70, -1000, 10699, -1000, -1000, 10699, 2856, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 208, -1000, -1000, -1000, -1000, 695, - 6211, 6211, 3836, 6211, -1000, -1000, -1000, 739, -1000, 769, - 810, -1000, 722, 720, 5512, -1000, -1000, 147, 156, -1000, - -1000, 328, -1000, -1000, -1000, -1000, 94, 429, -1000, 1907, - -1000, -1000, -1000, -1000, 284, 6657, 6657, 6657, 1409, 1907, - 1872, 405, 357, 113, 612, 612, 112, 112, 112, 112, - 112, 910, 910, -1000, -1000, -1000, 364, -1000, -1000, -1000, - 364, 5512, 582, -1000, -1000, 6211, -1000, 364, 426, 426, - 289, 334, 626, -1000, 91, 619, 426, 5512, 218, -1000, - 6211, 364, -1000, 426, 364, 426, 426, 544, 429, -1000, - 564, -1000, 172, 874, 605, 652, 650, -1000, -1000, -1000, - -1000, 675, -1000, 636, -1000, -1000, -1000, -1000, -1000, 58, - 57, 56, 10253, -1000, 818, 8914, 521, -1000, -1000, 581, - -121, -100, -1000, -1000, -1000, 180, -1000, 428, 530, 2366, - -1000, -1000, -1000, -1000, -1000, -1000, 601, 749, 145, 137, - 427, -1000, -1000, 736, -1000, 238, -69, -1000, -1000, 292, - -33, -33, -1000, -1000, 110, 730, 110, 110, 110, 343, - 343, -1000, -1000, -1000, -1000, 280, -1000, -1000, -1000, 277, - -1000, 637, 10253, 2856, -1000, 3591, -1000, -1000, -1000, -1000, - -1000, -1000, 282, 204, 179, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 13, -1000, 2856, -1000, - 209, 10699, 10699, 709, 180, 180, 79, -1000, -1000, 10699, - -1000, -1000, -1000, -1000, 610, -1000, -1000, -1000, 3101, 5512, - -1000, 1409, 1907, 1606, -1000, 6657, 6657, -1000, -1000, 426, - 5512, 180, -1000, -1000, -1000, 54, 327, 54, 6657, 6657, - 3836, 6657, 6657, -168, 532, 187, -1000, 6211, 307, -1000, - -1000, -1000, -1000, -1000, 635, 10476, 429, -1000, 7790, 10253, - 802, 10476, 6211, 6211, -1000, -1000, 6211, 599, -1000, 6211, - -1000, -1000, -1000, 429, 429, 429, 389, -1000, 802, 521, - -1000, -1000, -1000, -130, -132, -1000, -1000, 2611, -1000, 2611, - 10253, -1000, 367, 350, -1000, -1000, 625, 28, -1000, -1000, - -1000, 423, 110, 110, -1000, 155, -1000, -1000, -1000, 420, - -1000, 416, 526, 410, 10699, -1000, -1000, 516, -1000, 165, - -1000, -1000, 10253, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 10253, 10699, -1000, -1000, -1000, - -1000, -1000, 10253, -1000, -1000, 341, 6211, -1000, -1000, -1000, - 3591, -1000, 818, 8914, -1000, -1000, 364, -1000, 6657, 1907, - 1907, -1000, -1000, 364, 595, 595, -1000, 595, 597, -1000, - 595, -15, 595, -16, 364, 364, 1524, 1728, -1000, 422, - 1553, 429, -165, -1000, 180, 6211, -1000, 732, 490, 498, - -1000, -1000, 5280, 364, 391, 77, 389, 776, -1000, 180, - 180, 180, 10253, 180, 10253, 10253, 10253, 7567, 10253, 776, - -1000, -1000, -1000, -1000, 2366, -1000, 387, -1000, 595, -1000, - -1000, -60, 828, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -33, 340, -33, 259, -1000, 257, - 2856, 3591, 2611, -1000, 594, -1000, -1000, -1000, -1000, 741, - -1000, 180, 815, 513, -1000, 1907, -1000, -1000, 86, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 6657, 6657, - -1000, 6657, 6657, 6657, 364, 322, 180, 748, -1000, 429, - -1000, -1000, 560, 10253, 10253, -1000, -1000, 377, -1000, 371, - 371, 371, 125, -1000, -1000, 107, 10253, -1000, 133, -1000, - -147, 110, -1000, 110, 417, 406, -1000, -1000, -1000, 10253, - 429, 805, 779, -1000, -1000, 1509, 1509, 1509, 1509, 16, - -1000, -1000, 826, -1000, 429, -1000, 593, 73, -1000, 10253, - -1000, -1000, -1000, -1000, -1000, 107, -1000, 347, 160, 317, - -1000, 239, 747, -1000, 738, -1000, -1000, -1000, -1000, -1000, - 363, 12, -1000, 6211, 6211, -1000, -1000, -1000, -1000, 364, - 49, -178, 10476, 498, 364, 10253, -1000, -1000, -1000, 256, - -1000, -1000, -1000, 316, -1000, -1000, 606, 361, -1000, 10253, - 180, 494, -1000, 706, -171, -181, 435, -1000, -1000, -1000, - -1000, -174, -1000, 12, 715, -1000, 705, -1000, -1000, -1000, - 9, -175, 4, -179, 429, -182, 6434, -1000, 1509, 364, - -1000, -1000, -} -var yyPgo = [...]int{ - - 0, 1069, 13, 493, 1068, 1067, 1063, 1059, 1058, 1056, - 1055, 1053, 1052, 1047, 1045, 1044, 1042, 1040, 1039, 1037, - 1036, 1035, 1033, 1032, 104, 1031, 1027, 1026, 57, 1025, - 63, 1024, 1022, 33, 225, 45, 30, 150, 1018, 31, - 54, 84, 1017, 35, 1016, 1014, 70, 1013, 51, 1000, - 999, 1293, 998, 995, 19, 41, 993, 991, 990, 989, - 60, 312, 988, 987, 985, 982, 981, 979, 39, 5, - 7, 12, 11, 978, 127, 15, 976, 55, 975, 974, - 973, 971, 25, 970, 46, 965, 21, 40, 964, 16, - 53, 28, 23, 2, 65, 47, 962, 27, 50, 38, - 961, 958, 367, 948, 944, 942, 940, 936, 934, 140, - 309, 932, 931, 930, 928, 32, 167, 466, 73, 58, - 927, 926, 925, 1239, 59, 52, 22, 924, 36, 1247, - 42, 912, 910, 29, 909, 908, 897, 895, 894, 893, - 892, 264, 890, 889, 887, 17, 20, 882, 881, 49, - 26, 878, 877, 876, 34, 37, 874, 44, 873, 872, - 867, 866, 24, 10, 865, 9, 862, 8, 860, 856, - 4, 853, 18, 852, 3, 851, 6, 43, 850, 847, - 0, 323, 844, 843, 105, -} -var yyR1 = [...]int{ - - 0, 178, 179, 179, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 2, 6, 3, 4, 4, 5, - 5, 7, 7, 27, 27, 8, 9, 9, 9, 182, - 182, 46, 46, 90, 90, 10, 10, 10, 10, 95, - 95, 99, 99, 99, 100, 100, 100, 100, 131, 131, - 11, 11, 11, 11, 11, 11, 11, 176, 176, 175, - 174, 174, 173, 173, 172, 16, 159, 160, 160, 160, - 155, 134, 134, 134, 134, 137, 137, 135, 135, 135, - 135, 135, 135, 135, 136, 136, 136, 136, 136, 138, - 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, - 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, - 140, 140, 140, 140, 140, 140, 140, 154, 154, 141, - 141, 149, 149, 150, 150, 150, 147, 147, 148, 148, - 151, 151, 151, 142, 142, 142, 142, 142, 142, 142, - 144, 144, 152, 152, 145, 145, 145, 146, 146, 153, - 153, 153, 153, 153, 143, 143, 156, 156, 168, 168, - 167, 167, 167, 158, 158, 164, 164, 164, 164, 164, - 157, 157, 166, 166, 165, 161, 161, 161, 162, 162, - 162, 163, 163, 163, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 177, 177, 177, 177, 177, 177, 177, - 177, 177, 177, 177, 171, 169, 169, 170, 170, 13, - 14, 14, 14, 14, 14, 15, 15, 17, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 107, 107, 104, 104, 105, 105, 106, 106, 106, - 108, 108, 108, 132, 132, 132, 19, 19, 21, 21, - 22, 23, 20, 20, 20, 20, 20, 183, 24, 25, - 25, 26, 26, 26, 30, 30, 30, 28, 28, 29, - 29, 35, 35, 34, 34, 36, 36, 36, 36, 120, - 120, 120, 119, 119, 38, 38, 39, 39, 40, 40, - 41, 41, 41, 53, 53, 89, 89, 91, 91, 42, - 42, 42, 42, 43, 43, 44, 44, 45, 45, 127, - 127, 126, 126, 126, 125, 125, 47, 47, 47, 49, - 48, 48, 48, 48, 50, 50, 52, 52, 51, 51, - 54, 54, 54, 54, 55, 55, 37, 37, 37, 37, - 37, 37, 37, 103, 103, 57, 57, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 67, 67, 67, - 67, 67, 67, 58, 58, 58, 58, 58, 58, 58, - 33, 33, 68, 68, 68, 74, 69, 69, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 65, - 65, 65, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, - 64, 64, 64, 64, 64, 184, 184, 66, 66, 66, - 66, 31, 31, 31, 31, 31, 130, 130, 133, 133, - 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, - 133, 78, 78, 32, 32, 76, 76, 77, 79, 79, - 75, 75, 75, 60, 60, 60, 60, 60, 60, 60, - 60, 62, 62, 62, 80, 80, 81, 81, 82, 82, - 83, 83, 84, 85, 85, 85, 86, 86, 86, 86, - 87, 87, 87, 59, 59, 59, 59, 59, 59, 88, - 88, 88, 88, 92, 92, 70, 70, 72, 72, 71, - 73, 93, 93, 97, 94, 94, 98, 98, 98, 96, - 96, 96, 122, 122, 122, 101, 101, 109, 109, 110, - 110, 102, 102, 111, 111, 111, 111, 111, 111, 111, - 111, 111, 111, 112, 112, 112, 113, 113, 114, 114, - 114, 121, 121, 117, 117, 118, 118, 123, 123, 124, - 124, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 180, 181, 128, 129, 129, 129, -} -var yyR2 = [...]int{ - - 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 4, 6, 7, 5, 10, 1, 3, 1, - 3, 7, 8, 1, 1, 8, 8, 7, 6, 1, - 1, 1, 3, 0, 4, 3, 4, 5, 4, 1, - 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, - 2, 8, 4, 6, 5, 5, 5, 0, 2, 1, - 0, 2, 1, 3, 3, 4, 4, 1, 3, 3, - 8, 3, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, - 2, 2, 2, 1, 4, 4, 2, 2, 3, 3, - 3, 3, 1, 1, 1, 1, 1, 6, 6, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, - 3, 0, 5, 0, 3, 5, 0, 1, 0, 1, - 0, 1, 2, 0, 2, 2, 2, 2, 2, 2, - 0, 3, 0, 1, 0, 3, 3, 0, 2, 0, - 2, 1, 2, 1, 0, 2, 5, 4, 1, 2, - 2, 3, 2, 0, 1, 2, 3, 3, 2, 2, - 1, 1, 1, 3, 2, 0, 1, 3, 1, 2, - 3, 1, 1, 1, 6, 7, 7, 12, 7, 7, - 7, 4, 5, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 7, 1, 3, 8, 8, 5, - 4, 6, 5, 4, 4, 3, 2, 3, 4, 4, - 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, - 4, 3, 6, 4, 2, 4, 2, 2, 2, 2, - 3, 1, 1, 0, 1, 0, 1, 0, 2, 2, - 0, 2, 2, 0, 1, 1, 2, 1, 1, 2, - 1, 1, 2, 2, 2, 2, 2, 0, 2, 0, - 2, 1, 2, 2, 0, 1, 1, 0, 1, 0, - 1, 0, 1, 1, 3, 1, 2, 3, 5, 0, - 1, 2, 1, 1, 0, 2, 1, 3, 1, 1, - 1, 3, 3, 3, 7, 1, 3, 1, 3, 4, - 4, 4, 3, 2, 4, 0, 1, 0, 2, 0, - 1, 0, 1, 2, 1, 1, 1, 2, 2, 1, - 2, 3, 2, 3, 2, 2, 2, 1, 1, 3, - 0, 5, 5, 5, 0, 2, 1, 3, 3, 2, - 3, 1, 2, 0, 3, 1, 1, 3, 3, 4, - 4, 5, 3, 4, 5, 6, 2, 1, 2, 1, - 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, - 0, 2, 1, 1, 1, 3, 1, 3, 1, 1, - 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, - 2, 2, 2, 2, 3, 1, 1, 1, 1, 4, - 5, 6, 4, 4, 6, 6, 6, 6, 8, 8, - 6, 8, 8, 9, 7, 5, 4, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 2, 4, 4, 4, - 4, 0, 3, 4, 7, 3, 1, 1, 2, 3, - 3, 1, 2, 2, 1, 2, 1, 2, 2, 1, - 2, 0, 1, 0, 2, 1, 2, 4, 0, 2, - 1, 3, 5, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 0, 3, 0, 2, 0, 3, - 1, 3, 2, 0, 1, 1, 0, 2, 4, 4, - 0, 2, 4, 2, 1, 3, 5, 4, 6, 1, - 3, 3, 5, 0, 5, 1, 3, 1, 2, 3, - 1, 1, 3, 3, 1, 3, 3, 3, 3, 1, - 2, 1, 1, 1, 1, 1, 1, 0, 2, 0, - 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, - 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 1, 1, -} -var yyChk = [...]int{ - - -1000, -178, -1, -2, -6, -7, -8, -9, -10, -11, - -12, -13, -14, -15, -17, -18, -19, -21, -22, -23, - -20, -3, -4, 6, 7, -27, 9, 10, 30, -16, - 112, 113, 115, 114, 140, 116, 133, 49, 152, 153, - 155, 156, 25, 134, 135, 138, 139, -180, 8, 235, - 53, -179, 250, -82, 15, -26, 5, -24, -183, -24, - -24, -24, -24, -24, -159, 53, -114, 121, 70, 148, - 227, 118, 119, 125, -117, 56, -116, 243, 152, 163, - 157, 184, 176, 174, 177, 214, 65, 155, 223, 136, - 172, 168, 166, 27, 189, 248, 167, 131, 130, 190, - 194, 215, 161, 162, 217, 188, 132, 32, 245, 34, - 144, 218, 192, 187, 183, 186, 160, 182, 38, 196, - 195, 197, 213, 179, 169, 18, 221, 139, 142, 191, - 193, 126, 146, 247, 219, 165, 143, 138, 222, 156, - 216, 225, 37, 201, 159, 129, 153, 150, 180, 145, - 170, 171, 185, 158, 181, 154, 147, 140, 224, 202, - 249, 178, 175, 151, 149, 206, 207, 208, 209, 246, - 220, 173, 203, -102, 121, 123, 119, 119, 120, 121, - 227, 118, 119, -51, -123, 56, -116, 121, 148, 119, - 106, 177, 112, 204, 120, 32, 146, -132, 119, -104, - 149, 206, 207, 208, 209, 56, 216, 215, 210, -123, - 154, -128, -128, -128, -128, -128, -2, -86, 17, 16, - -5, -3, -180, 6, 20, 21, -30, 39, 40, -25, - -36, 97, -37, -123, -56, 72, -61, 29, 56, -116, - 23, -60, -57, -75, -73, -74, 106, 107, 95, 96, - 103, 73, 108, -65, -63, -64, -66, 58, 57, 66, - 59, 60, 61, 62, 67, 68, 69, -117, -71, -180, - 43, 44, 236, 237, 238, 239, 242, 240, 75, 33, - 226, 234, 233, 232, 230, 231, 228, 229, 124, 227, - 101, 235, -102, -39, -40, -41, -42, -53, -74, -180, - -51, 11, -46, -51, -94, -131, 154, -98, 216, 215, - -118, -96, -117, -115, 214, 177, 213, 117, 71, 22, - 24, 199, 74, 106, 16, 75, 105, 236, 112, 47, - 228, 229, 226, 238, 239, 227, 204, 29, 10, 25, - 134, 21, 99, 114, 78, 79, 137, 23, 135, 69, - 19, 50, 11, 13, 14, 124, 123, 90, 120, 45, - 8, 108, 26, 87, 41, 28, 43, 88, 17, 230, - 231, 31, 242, 141, 101, 48, 35, 72, 67, 51, - 70, 15, 46, 89, 115, 235, 44, 118, 6, 241, - 30, 133, 42, 119, 205, 77, 122, 68, 5, 125, - 9, 49, 52, 232, 233, 234, 33, 76, 12, -160, - -155, 56, 120, -51, 235, -117, -110, 124, -110, -110, - 119, -51, -51, -109, 124, 56, -109, -109, -109, -51, - 109, -51, 56, 30, 227, 56, 146, 119, 147, 121, - -129, -180, -118, -129, -129, -129, 150, 151, -129, -105, - 211, 51, -129, -181, 55, -87, 19, 31, -37, -123, - -83, -84, -37, -82, -2, -24, 35, -28, 21, 64, - 11, -120, 71, 70, 87, -119, 22, -117, 58, 109, - -37, -58, 90, 72, 88, 89, 74, 92, 91, 102, - 95, 96, 97, 98, 99, 100, 101, 93, 94, 105, - 80, 81, 82, 83, 84, 85, 86, -103, -180, -74, - -180, 110, 111, -61, -61, -61, -61, -61, -61, -61, - -180, -2, -69, -37, -180, -180, -180, -180, -180, -180, - -180, -180, -180, -78, -37, -180, -184, -180, -184, -184, - -184, -184, -184, -184, -184, -180, -180, -180, -180, -52, - 26, -51, 30, 54, -47, -49, -48, -50, 41, 45, - 47, 42, 43, 44, 48, -127, 22, -39, -180, -126, - 142, -125, 22, -123, 58, -51, -46, -182, 54, 11, - 52, 54, -94, 154, -95, -99, 217, 219, 80, -122, - -117, 58, 29, 30, 55, 54, -134, -137, -139, -138, - -140, -135, -136, 174, 175, 106, 178, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 30, 136, 170, - 171, 172, 173, 190, 191, 192, 193, 194, 195, 196, - 197, 157, 158, 159, 160, 161, 162, 163, 165, 166, - 167, 168, 169, 56, -129, 121, -176, 52, 56, 72, - 56, -51, -51, -129, 122, -51, 23, 51, -51, 56, - 56, -124, -123, -115, -129, -129, -129, -129, -129, -129, - -129, -129, -129, -129, -107, 205, 212, -51, 9, 90, - 54, 18, 109, 54, -85, 24, 25, -86, -181, -30, - -62, -117, 59, 62, -29, 42, -51, -37, -37, -67, - 67, 72, 68, 69, -119, 97, -124, -118, -115, -61, - -68, -71, -74, 63, 90, 88, 89, 74, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -130, 56, 58, 56, -60, -60, -117, - -35, 21, -34, -36, -181, 54, -181, -2, -34, -34, - -37, -37, -75, -117, -123, -75, -34, -28, -76, -77, - 76, -75, -181, -34, -35, -34, -34, -90, 142, -51, - -93, -97, -75, -40, -41, -41, -40, -41, 41, 41, - 41, 46, 41, 46, 41, -48, -123, -181, -54, 49, - 123, 50, -180, -125, -90, 52, -39, -51, -98, -95, - 54, 218, 220, 221, 51, -37, -146, 105, -161, -162, - -163, -118, 58, 59, -155, -156, -164, 126, 129, 125, - -157, 120, 28, -151, 67, 72, -147, 202, -141, 53, - -141, -141, -141, -141, -145, 177, -145, -145, -145, 53, - 53, -141, -141, -141, -149, 53, -149, -149, -150, 53, - -150, -121, 52, -51, -174, 246, -175, 56, -129, 23, - -129, -111, 117, 114, 115, -171, 113, 199, 177, 65, - 29, 15, 236, 142, 249, 56, 143, -51, -51, -129, - -106, 11, 90, 37, -37, -37, -124, -84, -87, -101, - 19, 11, 33, 33, -34, 67, 68, 69, 109, -180, - -68, -61, -61, -61, -33, 137, 71, -181, -181, -34, - 54, -37, -181, -181, -181, 54, 52, 22, 54, 11, - 109, 54, 11, -181, -34, -79, -77, 78, -37, -181, - -181, -181, -181, -181, -59, 30, 33, -2, -180, -180, - -55, 54, 12, 80, -44, -43, 51, 52, -45, 51, - -43, 41, 41, 120, 120, 120, -91, -117, -55, -39, - -55, -99, -100, 222, 219, 225, 56, 54, -163, 80, - 53, 28, -157, -157, 56, 56, -142, 29, 67, -148, - 203, 59, -145, -145, -146, 30, -146, -146, -146, -154, - 58, -154, 59, 59, 51, -117, -129, -173, -172, -118, - -128, -177, 148, 127, 128, 131, 130, 56, 120, 28, - 126, 129, 142, 125, -177, 148, -112, -113, 122, 22, - 120, 28, 142, -129, -108, 88, 12, -123, -123, 38, - 109, -51, -38, 11, 97, -118, -35, -33, 71, -61, - -61, -181, -36, -133, 106, 174, 136, 172, 168, 188, - 179, 201, 170, 202, -130, -133, -61, -61, -118, -61, - -61, 243, -82, 79, -37, 77, -92, 51, -93, -70, - -72, -71, -180, -2, -88, -117, -91, -82, -97, -37, - -37, -37, 53, -37, -180, -180, -180, -181, 54, -82, - -55, 219, 223, 224, -162, -163, -166, -165, -117, 56, - 56, -144, 51, 58, 59, 60, 67, 226, 66, 55, - -146, -146, 56, 106, 55, 54, 55, 54, 55, 54, - -51, 54, 80, -128, -117, -128, -117, -51, -128, -117, - 58, -37, -55, -39, -181, -61, -181, -141, -141, -141, - -150, -141, 162, -141, 162, -181, -181, -181, 54, 19, - -181, 54, 19, -180, -32, 241, -37, 27, -92, 54, - -181, -181, -181, 54, 109, -181, -86, -89, -117, -89, - -89, -89, -126, -117, -86, 55, 54, -141, -152, 199, - 9, -145, 58, -145, 59, 59, -129, -172, -163, 53, - 26, -80, 13, -145, 56, -61, -61, -61, -61, -61, - -181, 58, 28, -72, 33, -2, -180, -117, -117, 54, - 55, -181, -181, -181, -54, -168, -167, 52, 132, 65, - -165, -153, 126, 28, 125, 226, -146, -146, 55, 55, - -89, -180, -81, 14, 16, -181, -181, -181, -181, -31, - 90, 246, 9, -70, -2, 109, -117, -167, 56, -158, - 80, 58, -143, 65, 28, 28, 55, -169, -170, 142, - -37, -69, -181, 244, 48, 247, -93, -181, -117, 59, - 58, -176, -181, 54, -117, 38, 245, 248, -174, -170, - 33, 38, 144, 246, 145, 247, -180, 248, -61, 141, - -181, -181, -} -var yyDef = [...]int{ - - 0, -2, 2, -2, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 508, 0, 277, 277, 277, 277, 277, 277, 0, - 578, 561, 0, 0, 0, 0, -2, 267, 268, 0, - 270, 271, 783, 783, 783, 783, 783, 0, 33, 34, - 781, 1, 3, 516, 0, 0, 281, 284, 279, 0, - 561, 0, 0, 0, 60, 0, 0, 770, 0, 771, - 559, 559, 559, 579, 580, 583, 584, 683, 684, 685, - 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, - 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, - 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, - 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, - 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, - 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, - 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, - 766, 767, 768, 769, 772, 773, 774, 775, 776, 777, - 778, 779, 780, 0, 0, 562, 0, 557, 0, 557, - 557, 557, 0, 226, 348, 587, 588, 770, 771, 0, - 0, 0, 0, 784, 784, 784, 784, 0, 784, 255, - 244, 246, 247, 248, 249, 784, 264, 265, 254, 266, - 269, 272, 273, 274, 275, 276, 27, 520, 0, 0, - 508, 29, 0, 277, 282, 283, 287, 285, 286, 278, - 0, 295, 299, 0, 356, 0, 361, 363, -2, -2, - 0, 398, 399, 400, 401, 402, 0, 0, 0, 0, - 0, 0, 0, 425, 426, 427, 428, 493, 494, 495, - 496, 497, 498, 499, 500, 365, 366, 490, 540, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 481, 0, - 455, 455, 455, 455, 455, 455, 455, 455, 0, 0, - 0, 0, 0, 0, 306, 308, 309, 310, 329, 0, - 331, 0, 0, 41, 45, 0, 761, 544, -2, -2, - 0, 0, 585, 586, -2, 690, -2, 591, 592, 593, - 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, - 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, - 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, - 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, - 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, - 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, - 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, - 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, - 674, 675, 676, 677, 678, 679, 680, 681, 682, 0, - 77, 0, 0, 784, 0, 67, 0, 0, 0, 0, - 0, 784, 0, 0, 0, 0, 0, 0, 0, 225, - 0, 227, 784, 784, 784, 784, 784, 784, 784, 784, - 236, 785, 786, 237, 238, 239, 784, 784, 241, 0, - 256, 0, 250, 28, 782, 22, 0, 0, 517, 0, - 509, 510, 513, 516, 27, 284, 0, 289, 288, 280, - 0, 296, 0, 0, 0, 300, 0, 302, 303, 0, - 359, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 383, 384, 385, 386, 387, 388, 389, 362, 0, 376, - 0, 0, 0, 418, 419, 420, 421, 422, 423, 0, - 291, 27, 0, 396, 0, 0, 0, 0, 0, 0, - 0, 0, 287, 0, 482, 0, 447, 0, 448, 449, - 450, 451, 452, 453, 454, 0, 291, 0, 0, 43, - 0, 347, 0, 0, 0, 0, 0, 0, 336, 0, - 0, 339, 0, 0, 0, 0, 330, 0, 0, 350, - 734, 332, 0, 334, 335, -2, 0, 0, 0, 39, - 40, 0, 46, 761, 48, 49, 0, 0, 0, 157, - 552, 553, 554, 550, 185, 0, 140, 136, 82, 83, - 84, 129, 86, 129, 129, 129, 129, 154, 154, 154, - 154, 112, 113, 114, 115, 116, 0, 0, 99, 129, - 129, 129, 103, 119, 120, 121, 122, 123, 124, 125, - 126, 87, 88, 89, 90, 91, 92, 93, 131, 131, - 131, 133, 133, 581, 62, 0, 70, 0, 784, 0, - 784, 75, 0, 201, 0, 220, 558, 0, 784, 223, - 224, 349, 589, 590, 228, 229, 230, 231, 232, 233, - 234, 235, 240, 243, 257, 251, 252, 245, 521, 0, - 0, 0, 0, 0, 512, 514, 515, 520, 30, 287, - 0, 501, 0, 0, 0, 290, 25, 357, 358, 360, - 377, 0, 379, 381, 301, 297, 0, 491, -2, 367, - 368, 392, 393, 394, 0, 0, 0, 0, 390, 372, - 0, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 417, 466, 467, 0, 415, 416, 424, - 0, 0, 292, 293, 395, 0, 539, 27, 0, 0, - 0, 0, 0, 490, 0, 0, 0, 0, 488, 485, - 0, 0, 456, 0, 0, 0, 0, 0, 0, 346, - 354, 541, 0, 307, 325, 327, 0, 322, 337, 338, - 340, 0, 342, 0, 344, 345, 311, 312, 313, 0, - 0, 0, 0, 333, 354, 0, 354, 42, 545, 47, - 0, 0, 52, 53, 546, 547, 548, 0, 76, 186, - 188, 191, 192, 193, 78, 79, 0, 0, 0, 0, - 0, 180, 181, 143, 141, 0, 138, 137, 85, 0, - 154, 154, 106, 107, 157, 0, 157, 157, 157, 0, - 0, 100, 101, 102, 94, 0, 95, 96, 97, 0, - 98, 0, 0, 784, 64, 0, 68, 69, 65, 560, - 66, 783, 0, 0, 573, 202, 563, 564, 565, 566, - 567, 568, 569, 570, 571, 572, 0, 219, 784, 222, - 260, 0, 0, 0, 518, 519, 0, 511, 23, 0, - 555, 556, 502, 503, 304, 378, 380, 382, 0, 291, - 369, 390, 373, 0, 370, 0, 0, 364, 429, 0, - 0, 397, -2, 432, 433, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 508, 0, 486, 0, 0, 446, - 457, 458, 459, 460, 533, 0, 0, -2, 0, 0, - 508, 0, 0, 0, 319, 326, 0, 0, 320, 0, - 321, 341, 343, 0, 0, 0, 0, 317, 508, 354, - 38, 50, 51, 0, 0, 57, 158, 0, 189, 0, - 0, 175, 0, 0, 178, 179, 150, 0, 142, 81, - 139, 0, 157, 157, 108, 0, 109, 110, 111, 0, - 127, 0, 0, 0, 0, 582, 63, 71, 72, 0, - 194, 783, 0, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 783, 0, 0, 783, 574, 575, - 576, 577, 0, 221, 242, 0, 0, 258, 259, 522, - 0, 24, 354, 0, 298, 492, 0, 371, 0, 391, - 374, 430, 294, 0, 129, 129, 471, 129, 133, 474, - 129, 476, 129, 479, 0, 0, 0, 0, 491, 0, - 0, 0, 483, 445, 489, 0, 31, 0, 533, 523, - 535, 537, 0, 27, 0, 529, 0, 516, 542, 355, - 543, 323, 0, 328, 0, 0, 0, 331, 0, 516, - 37, 54, 55, 56, 187, 190, 0, 182, 129, 176, - 177, 152, 0, 144, 145, 146, 147, 148, 149, 130, - 104, 105, 155, 156, 154, 0, 154, 0, 134, 0, - 784, 0, 0, 195, 0, 196, 198, 199, 200, 0, - 261, 262, 504, 305, 431, 375, 434, 468, 154, 472, - 473, 475, 477, 478, 480, 436, 435, 437, 0, 0, - 440, 0, 0, 0, 0, 0, 487, 0, 32, 0, - 538, -2, 0, 0, 0, 44, 35, 0, 315, 0, - 0, 0, 350, 318, 36, 167, 0, 184, 159, 153, - 0, 157, 128, 157, 0, 0, 61, 73, 74, 0, - 0, 506, 0, 469, 470, 0, 0, 0, 0, 461, - 444, 484, 0, 536, 0, -2, 0, 531, 530, 0, - 324, 351, 352, 353, 314, 166, 168, 0, 173, 0, - 183, 164, 0, 161, 163, 151, 117, 118, 132, 135, - 0, 0, 26, 0, 0, 438, 439, 441, 442, 0, - 0, 0, 0, 526, 27, 0, 316, 169, 170, 0, - 174, 172, 80, 0, 160, 162, 67, 0, 215, 0, - 507, 505, 443, 0, 0, 0, 534, -2, 532, 171, - 165, 70, 214, 0, 0, 462, 0, 465, 197, 216, - 0, 463, 0, 0, 0, 0, 0, 464, 0, 0, - 217, 218, -} -var yyTok1 = [...]int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 73, 3, 3, 3, 100, 92, 3, - 53, 55, 97, 95, 54, 96, 109, 98, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 250, - 81, 80, 82, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 102, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 91, 3, 103, -} -var yyTok2 = [...]int{ - - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, - 76, 77, 78, 79, 83, 84, 85, 86, 87, 88, - 89, 90, 93, 94, 99, 101, 104, 105, 106, 107, - 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, -} -var yyTok3 = [...]int{ - 0, -} - -var yyErrorMessages = [...]struct { - state int - token int - msg string -}{} - -//line yaccpar:1 - -/* parser for yacc output */ - -var ( - yyDebug = 0 - yyErrorVerbose = false -) - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -type yyParser interface { - Parse(yyLexer) int - Lookahead() int -} - -type yyParserImpl struct { - lval yySymType - stack [yyInitialStackSize]yySymType - char int -} - -func (p *yyParserImpl) Lookahead() int { - return p.char -} - -func yyNewParser() yyParser { - return &yyParserImpl{} -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - if c >= 1 && c-1 < len(yyToknames) { - if yyToknames[c-1] != "" { - return yyToknames[c-1] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yyErrorMessage(state, lookAhead int) string { - const TOKSTART = 4 - - if !yyErrorVerbose { - return "syntax error" - } - - for _, e := range yyErrorMessages { - if e.state == state && e.token == lookAhead { - return "syntax error: " + e.msg - } - } - - res := "syntax error: unexpected " + yyTokname(lookAhead) - - // To match Bison, suggest at most four expected tokens. - expected := make([]int, 0, 4) - - // Look for shiftable tokens. - base := yyPact[state] - for tok := TOKSTART; tok-1 < len(yyToknames); tok++ { - if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok { - if len(expected) == cap(expected) { - return res - } - expected = append(expected, tok) - } - } - - if yyDef[state] == -2 { - i := 0 - for yyExca[i] != -1 || yyExca[i+1] != state { - i += 2 - } - - // Look for tokens that we accept or reduce. - for i += 2; yyExca[i] >= 0; i += 2 { - tok := yyExca[i] - if tok < TOKSTART || yyExca[i+1] == 0 { - continue - } - if len(expected) == cap(expected) { - return res - } - expected = append(expected, tok) - } - - // If the default action is to accept or reduce, give up. - if yyExca[i+1] != 0 { - return res - } - } - - for i, tok := range expected { - if i == 0 { - res += ", expecting " - } else { - res += " or " - } - res += yyTokname(tok) - } - return res -} - -func yylex1(lex yyLexer, lval *yySymType) (char, token int) { - token = 0 - char = lex.Lex(lval) - if char <= 0 { - token = yyTok1[0] - goto out - } - if char < len(yyTok1) { - token = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - token = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - token = yyTok3[i+0] - if token == char { - token = yyTok3[i+1] - goto out - } - } - -out: - if token == 0 { - token = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) - } - return char, token -} - -func yyParse(yylex yyLexer) int { - return yyNewParser().Parse(yylex) -} - -func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { - var yyn int - var yyVAL yySymType - var yyDollar []yySymType - _ = yyDollar // silence set and not used - yyS := yyrcvr.stack[:] - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yyrcvr.char = -1 - yytoken := -1 // yyrcvr.char translated into internal numbering - defer func() { - // Make sure we report no lookahead when not parsing. - yystate = -1 - yyrcvr.char = -1 - yytoken = -1 - }() - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yyrcvr.char < 0 { - yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) - } - yyn += yytoken - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yytoken { /* valid shift */ - yyrcvr.char = -1 - yytoken = -1 - yyVAL = yyrcvr.lval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yyrcvr.char < 0 { - yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yytoken { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error(yyErrorMessage(yystate, yytoken)) - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) - } - if yytoken == yyEofCode { - goto ret1 - } - yyrcvr.char = -1 - yytoken = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 1: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:302 - { - setParseTree(yylex, yyDollar[1].statement) - } - case 2: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:307 - { - } - case 3: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:308 - { - } - case 4: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:312 - { - yyVAL.statement = yyDollar[1].selStmt - } - case 22: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:335 - { - sel := yyDollar[1].selStmt.(*Select) - sel.OrderBy = yyDollar[2].orderBy - sel.Limit = yyDollar[3].limit - sel.Lock = yyDollar[4].str - yyVAL.selStmt = sel - } - case 23: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:343 - { - yyVAL.selStmt = &Union{Type: yyDollar[2].str, Left: yyDollar[1].selStmt, Right: yyDollar[3].selStmt, OrderBy: yyDollar[4].orderBy, Limit: yyDollar[5].limit, Lock: yyDollar[6].str} - } - case 24: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:347 - { - yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, SelectExprs: SelectExprs{Nextval{Expr: yyDollar[5].expr}}, From: TableExprs{&AliasedTableExpr{Expr: yyDollar[7].tableName}}} - } - case 25: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:353 - { - yyVAL.statement = &Stream{Comments: Comments(yyDollar[2].bytes2), SelectExpr: yyDollar[3].selectExpr, Table: yyDollar[5].tableName} - } - case 26: - yyDollar = yyS[yypt-10 : yypt+1] - //line sql.y:360 - { - yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, Distinct: yyDollar[4].str, Hints: yyDollar[5].str, SelectExprs: yyDollar[6].selectExprs, From: yyDollar[7].tableExprs, Where: NewWhere(WhereStr, yyDollar[8].expr), GroupBy: GroupBy(yyDollar[9].exprs), Having: NewWhere(HavingStr, yyDollar[10].expr)} - } - case 27: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:366 - { - yyVAL.selStmt = yyDollar[1].selStmt - } - case 28: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:370 - { - yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} - } - case 29: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:376 - { - yyVAL.selStmt = yyDollar[1].selStmt - } - case 30: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:380 - { - yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} - } - case 31: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:387 - { - // insert_data returns a *Insert pre-filled with Columns & Values - ins := yyDollar[6].ins - ins.Action = yyDollar[1].str - ins.Comments = yyDollar[2].bytes2 - ins.Ignore = yyDollar[3].str - ins.Table = yyDollar[4].tableName - ins.Partitions = yyDollar[5].partitions - ins.OnDup = OnDup(yyDollar[7].updateExprs) - yyVAL.statement = ins - } - case 32: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:399 - { - cols := make(Columns, 0, len(yyDollar[7].updateExprs)) - vals := make(ValTuple, 0, len(yyDollar[8].updateExprs)) - for _, updateList := range yyDollar[7].updateExprs { - cols = append(cols, updateList.Name.Name) - vals = append(vals, updateList.Expr) - } - yyVAL.statement = &Insert{Action: yyDollar[1].str, Comments: Comments(yyDollar[2].bytes2), Ignore: yyDollar[3].str, Table: yyDollar[4].tableName, Partitions: yyDollar[5].partitions, Columns: cols, Rows: Values{vals}, OnDup: OnDup(yyDollar[8].updateExprs)} - } - case 33: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:411 - { - yyVAL.str = InsertStr - } - case 34: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:415 - { - yyVAL.str = ReplaceStr - } - case 35: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:421 - { - yyVAL.statement = &Update{Comments: Comments(yyDollar[2].bytes2), TableExprs: yyDollar[3].tableExprs, Exprs: yyDollar[5].updateExprs, Where: NewWhere(WhereStr, yyDollar[6].expr), OrderBy: yyDollar[7].orderBy, Limit: yyDollar[8].limit} - } - case 36: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:427 - { - yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), TableExprs: TableExprs{&AliasedTableExpr{Expr: yyDollar[4].tableName}}, Partitions: yyDollar[5].partitions, Where: NewWhere(WhereStr, yyDollar[6].expr), OrderBy: yyDollar[7].orderBy, Limit: yyDollar[8].limit} - } - case 37: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:431 - { - yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[4].tableNames, TableExprs: yyDollar[6].tableExprs, Where: NewWhere(WhereStr, yyDollar[7].expr)} - } - case 38: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:435 - { - yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[3].tableNames, TableExprs: yyDollar[5].tableExprs, Where: NewWhere(WhereStr, yyDollar[6].expr)} - } - case 39: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:440 - { - } - case 40: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:441 - { - } - case 41: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:445 - { - yyVAL.tableNames = TableNames{yyDollar[1].tableName} - } - case 42: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:449 - { - yyVAL.tableNames = append(yyVAL.tableNames, yyDollar[3].tableName) - } - case 43: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:454 - { - yyVAL.partitions = nil - } - case 44: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:458 - { - yyVAL.partitions = yyDollar[3].partitions - } - case 45: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:464 - { - yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[3].setExprs} - } - case 46: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:468 - { - yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[4].setExprs} - } - case 47: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:472 - { - yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[5].setExprs} - } - case 48: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:476 - { - yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[4].setExprs} - } - case 49: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:482 - { - yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} - } - case 50: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:486 - { - yyVAL.setExprs = append(yyVAL.setExprs, yyDollar[3].setExpr) - } - case 51: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:492 - { - yyVAL.setExpr = yyDollar[3].setExpr - } - case 52: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:496 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("0"))} - } - case 53: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:500 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("1"))} - } - case 54: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:506 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("repeatable read"))} - } - case 55: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:510 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read committed"))} - } - case 56: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:514 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read uncommitted"))} - } - case 57: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:518 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("serializable"))} - } - case 58: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:524 - { - yyVAL.str = SessionStr - } - case 59: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:528 - { - yyVAL.str = GlobalStr - } - case 60: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:534 - { - yyDollar[1].ddl.TableSpec = yyDollar[2].TableSpec - yyVAL.statement = yyDollar[1].ddl - } - case 61: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:539 - { - // Change this to an alter statement - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[7].tableName, NewName: yyDollar[7].tableName} - } - case 62: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:544 - { - yyVAL.statement = &DDL{Action: CreateStr, NewName: yyDollar[3].tableName.ToViewName()} - } - case 63: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:548 - { - yyVAL.statement = &DDL{Action: CreateStr, NewName: yyDollar[5].tableName.ToViewName()} - } - case 64: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:552 - { - yyVAL.statement = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{ - Name: yyDollar[3].colIdent, - Type: yyDollar[4].colIdent, - Params: yyDollar[5].vindexParams, - }} - } - case 65: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:560 - { - yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} - } - case 66: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:564 - { - yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} - } - case 67: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:569 - { - yyVAL.colIdent = NewColIdent("") - } - case 68: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:573 - { - yyVAL.colIdent = yyDollar[2].colIdent - } - case 69: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:579 - { - yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) - } - case 70: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:584 - { - var v []VindexParam - yyVAL.vindexParams = v - } - case 71: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:589 - { - yyVAL.vindexParams = yyDollar[2].vindexParams - } - case 72: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:595 - { - yyVAL.vindexParams = make([]VindexParam, 0, 4) - yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[1].vindexParam) - } - case 73: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:600 - { - yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[3].vindexParam) - } - case 74: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:606 - { - yyVAL.vindexParam = VindexParam{Key: yyDollar[1].colIdent, Val: yyDollar[3].str} - } - case 75: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:612 - { - yyVAL.ddl = &DDL{Action: CreateStr, NewName: yyDollar[4].tableName} - setDDL(yylex, yyVAL.ddl) - } - case 76: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:619 - { - yyVAL.TableSpec = yyDollar[2].TableSpec - yyVAL.TableSpec.Options = yyDollar[4].str - } - case 77: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:626 - { - yyVAL.TableSpec = &TableSpec{} - yyVAL.TableSpec.AddColumn(yyDollar[1].columnDefinition) - } - case 78: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:631 - { - yyVAL.TableSpec.AddColumn(yyDollar[3].columnDefinition) - } - case 79: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:635 - { - yyVAL.TableSpec.AddIndex(yyDollar[3].indexDefinition) - } - case 80: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:641 - { - yyDollar[2].columnType.NotNull = yyDollar[3].boolVal - yyDollar[2].columnType.Default = yyDollar[4].optVal - yyDollar[2].columnType.OnUpdate = yyDollar[5].optVal - yyDollar[2].columnType.Autoincrement = yyDollar[6].boolVal - yyDollar[2].columnType.KeyOpt = yyDollar[7].colKeyOpt - yyDollar[2].columnType.Comment = yyDollar[8].optVal - yyVAL.columnDefinition = &ColumnDefinition{Name: NewColIdent(string(yyDollar[1].bytes)), Type: yyDollar[2].columnType} - } - case 81: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:652 - { - yyVAL.columnType = yyDollar[1].columnType - yyVAL.columnType.Unsigned = yyDollar[2].boolVal - yyVAL.columnType.Zerofill = yyDollar[3].boolVal - } - case 85: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:663 - { - yyVAL.columnType = yyDollar[1].columnType - yyVAL.columnType.Length = yyDollar[2].optVal - } - case 86: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:668 - { - yyVAL.columnType = yyDollar[1].columnType - } - case 87: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:674 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 88: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:678 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 89: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:682 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 90: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:686 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 91: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:690 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 92: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:694 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 93: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:698 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 94: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:704 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 95: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:710 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 96: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:716 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 97: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:722 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 98: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:728 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 99: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:736 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 100: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:740 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 101: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:744 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 102: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:748 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 103: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:752 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 104: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:758 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} - } - case 105: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:762 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} - } - case 106: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:766 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 107: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:770 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 108: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:774 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} - } - case 109: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:778 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} - } - case 110: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:782 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} - } - case 111: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:786 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} - } - case 112: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:790 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 113: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:794 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 114: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:798 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 115: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:802 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 116: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:806 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 117: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:810 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} - } - case 118: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:815 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} - } - case 119: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:821 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 120: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:825 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 121: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:829 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 122: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:833 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 123: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:837 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 124: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:841 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 125: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:845 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 126: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:849 - { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - } - case 127: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:855 - { - yyVAL.strs = make([]string, 0, 4) - yyVAL.strs = append(yyVAL.strs, "'"+string(yyDollar[1].bytes)+"'") - } - case 128: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:860 - { - yyVAL.strs = append(yyDollar[1].strs, "'"+string(yyDollar[3].bytes)+"'") - } - case 129: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:865 - { - yyVAL.optVal = nil - } - case 130: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:869 - { - yyVAL.optVal = NewIntVal(yyDollar[2].bytes) - } - case 131: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:874 - { - yyVAL.LengthScaleOption = LengthScaleOption{} - } - case 132: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:878 - { - yyVAL.LengthScaleOption = LengthScaleOption{ - Length: NewIntVal(yyDollar[2].bytes), - Scale: NewIntVal(yyDollar[4].bytes), - } - } - case 133: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:886 - { - yyVAL.LengthScaleOption = LengthScaleOption{} - } - case 134: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:890 - { - yyVAL.LengthScaleOption = LengthScaleOption{ - Length: NewIntVal(yyDollar[2].bytes), - } - } - case 135: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:896 - { - yyVAL.LengthScaleOption = LengthScaleOption{ - Length: NewIntVal(yyDollar[2].bytes), - Scale: NewIntVal(yyDollar[4].bytes), - } - } - case 136: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:904 - { - yyVAL.boolVal = BoolVal(false) - } - case 137: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:908 - { - yyVAL.boolVal = BoolVal(true) - } - case 138: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:913 - { - yyVAL.boolVal = BoolVal(false) - } - case 139: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:917 - { - yyVAL.boolVal = BoolVal(true) - } - case 140: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:923 - { - yyVAL.boolVal = BoolVal(false) - } - case 141: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:927 - { - yyVAL.boolVal = BoolVal(false) - } - case 142: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:931 - { - yyVAL.boolVal = BoolVal(true) - } - case 143: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:936 - { - yyVAL.optVal = nil - } - case 144: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:940 - { - yyVAL.optVal = NewStrVal(yyDollar[2].bytes) - } - case 145: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:944 - { - yyVAL.optVal = NewIntVal(yyDollar[2].bytes) - } - case 146: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:948 - { - yyVAL.optVal = NewFloatVal(yyDollar[2].bytes) - } - case 147: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:952 - { - yyVAL.optVal = NewValArg(yyDollar[2].bytes) - } - case 148: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:956 - { - yyVAL.optVal = NewValArg(yyDollar[2].bytes) - } - case 149: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:960 - { - yyVAL.optVal = NewBitVal(yyDollar[2].bytes) - } - case 150: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:965 - { - yyVAL.optVal = nil - } - case 151: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:969 - { - yyVAL.optVal = NewValArg(yyDollar[3].bytes) - } - case 152: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:974 - { - yyVAL.boolVal = BoolVal(false) - } - case 153: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:978 - { - yyVAL.boolVal = BoolVal(true) - } - case 154: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:983 - { - yyVAL.str = "" - } - case 155: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:987 - { - yyVAL.str = string(yyDollar[3].bytes) - } - case 156: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:991 - { - yyVAL.str = string(yyDollar[3].bytes) - } - case 157: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:996 - { - yyVAL.str = "" - } - case 158: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1000 - { - yyVAL.str = string(yyDollar[2].bytes) - } - case 159: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1005 - { - yyVAL.colKeyOpt = colKeyNone - } - case 160: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1009 - { - yyVAL.colKeyOpt = colKeyPrimary - } - case 161: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1013 - { - yyVAL.colKeyOpt = colKey - } - case 162: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1017 - { - yyVAL.colKeyOpt = colKeyUniqueKey - } - case 163: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1021 - { - yyVAL.colKeyOpt = colKeyUnique - } - case 164: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1026 - { - yyVAL.optVal = nil - } - case 165: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1030 - { - yyVAL.optVal = NewStrVal(yyDollar[2].bytes) - } - case 166: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1036 - { - yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns, Options: yyDollar[5].indexOptions} - } - case 167: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1040 - { - yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns} - } - case 168: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1046 - { - yyVAL.indexOptions = []*IndexOption{yyDollar[1].indexOption} - } - case 169: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1050 - { - yyVAL.indexOptions = append(yyVAL.indexOptions, yyDollar[2].indexOption) - } - case 170: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1056 - { - yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Using: string(yyDollar[2].bytes)} - } - case 171: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1060 - { - // should not be string - yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewIntVal(yyDollar[3].bytes)} - } - case 172: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1065 - { - yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewStrVal(yyDollar[2].bytes)} - } - case 173: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1071 - { - yyVAL.str = "" - } - case 174: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1075 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 175: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1081 - { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].bytes), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} - } - case 176: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1085 - { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(string(yyDollar[3].bytes)), Spatial: true, Unique: false} - } - case 177: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1089 - { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(string(yyDollar[3].bytes)), Unique: true} - } - case 178: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1093 - { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes), Name: NewColIdent(string(yyDollar[2].bytes)), Unique: true} - } - case 179: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1097 - { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].str), Name: NewColIdent(string(yyDollar[2].bytes)), Unique: false} - } - case 180: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1103 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 181: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1107 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 182: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1113 - { - yyVAL.indexColumns = []*IndexColumn{yyDollar[1].indexColumn} - } - case 183: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1117 - { - yyVAL.indexColumns = append(yyVAL.indexColumns, yyDollar[3].indexColumn) - } - case 184: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1123 - { - yyVAL.indexColumn = &IndexColumn{Column: yyDollar[1].colIdent, Length: yyDollar[2].optVal} - } - case 185: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1128 - { - yyVAL.str = "" - } - case 186: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1132 - { - yyVAL.str = " " + string(yyDollar[1].str) - } - case 187: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1136 - { - yyVAL.str = string(yyDollar[1].str) + ", " + string(yyDollar[3].str) - } - case 188: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1144 - { - yyVAL.str = yyDollar[1].str - } - case 189: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1148 - { - yyVAL.str = yyDollar[1].str + " " + yyDollar[2].str - } - case 190: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1152 - { - yyVAL.str = yyDollar[1].str + "=" + yyDollar[3].str - } - case 191: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1158 - { - yyVAL.str = yyDollar[1].colIdent.String() - } - case 192: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1162 - { - yyVAL.str = "'" + string(yyDollar[1].bytes) + "'" - } - case 193: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1166 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 194: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1172 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} - } - case 195: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1176 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} - } - case 196: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1180 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} - } - case 197: - yyDollar = yyS[yypt-12 : yypt+1] - //line sql.y:1184 - { - yyVAL.statement = &DDL{ - Action: AddColVindexStr, - Table: yyDollar[4].tableName, - VindexSpec: &VindexSpec{ - Name: yyDollar[7].colIdent, - Type: yyDollar[11].colIdent, - Params: yyDollar[12].vindexParams, - }, - VindexCols: yyDollar[9].columns, - } - } - case 198: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1197 - { - yyVAL.statement = &DDL{ - Action: DropColVindexStr, - Table: yyDollar[4].tableName, - VindexSpec: &VindexSpec{ - Name: yyDollar[7].colIdent, - }, - } - } - case 199: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1207 - { - // Change this to a rename statement - yyVAL.statement = &DDL{Action: RenameStr, Table: yyDollar[4].tableName, NewName: yyDollar[7].tableName} - } - case 200: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1212 - { - // Rename an index can just be an alter - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} - } - case 201: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1217 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName.ToViewName(), NewName: yyDollar[3].tableName.ToViewName()} - } - case 202: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1221 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, PartitionSpec: yyDollar[5].partSpec} - } - case 214: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1240 - { - yyVAL.partSpec = &PartitionSpec{Action: ReorganizeStr, Name: yyDollar[3].colIdent, Definitions: yyDollar[6].partDefs} - } - case 215: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1246 - { - yyVAL.partDefs = []*PartitionDefinition{yyDollar[1].partDef} - } - case 216: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1250 - { - yyVAL.partDefs = append(yyDollar[1].partDefs, yyDollar[3].partDef) - } - case 217: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:1256 - { - yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Limit: yyDollar[7].expr} - } - case 218: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:1260 - { - yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Maxvalue: true} - } - case 219: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1266 - { - yyVAL.statement = &DDL{Action: RenameStr, Table: yyDollar[3].tableName, NewName: yyDollar[5].tableName} - } - case 220: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1272 - { - var exists bool - if yyDollar[3].byt != 0 { - exists = true - } - yyVAL.statement = &DDL{Action: DropStr, Table: yyDollar[4].tableName, IfExists: exists} - } - case 221: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1280 - { - // Change this to an alter statement - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[5].tableName, NewName: yyDollar[5].tableName} - } - case 222: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1285 - { - var exists bool - if yyDollar[3].byt != 0 { - exists = true - } - yyVAL.statement = &DDL{Action: DropStr, Table: yyDollar[4].tableName.ToViewName(), IfExists: exists} - } - case 223: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1293 - { - yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} - } - case 224: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1297 - { - yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} - } - case 225: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1303 - { - yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[3].tableName} - } - case 226: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1307 - { - yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[2].tableName} - } - case 227: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1312 - { - yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName, NewName: yyDollar[3].tableName} - } - case 228: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1318 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 229: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1322 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 230: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1326 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 231: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1331 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 232: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1335 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 233: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1339 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 234: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1343 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 235: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1347 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} - } - case 236: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1351 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 237: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1355 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 238: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1359 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 239: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1363 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 240: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1367 - { - yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} - } - case 241: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1371 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 242: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1375 - { - // this is ugly, but I couldn't find a better way for now - if yyDollar[4].str == "processlist" { - yyVAL.statement = &Show{Type: yyDollar[4].str} - } else { - showTablesOpt := &ShowTablesOpt{Extended: yyDollar[2].str, Full: yyDollar[3].str, DbName: yyDollar[5].str, Filter: yyDollar[6].showFilter} - yyVAL.statement = &Show{Type: yyDollar[4].str, ShowTablesOpt: showTablesOpt} - } - } - case 243: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1385 - { - yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} - } - case 244: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1389 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 245: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1393 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), OnTable: yyDollar[4].tableName} - } - case 246: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1397 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 247: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1401 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 248: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1405 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 249: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1409 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 250: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1419 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } - case 251: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1425 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 252: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1429 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 253: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1435 - { - yyVAL.str = "" - } - case 254: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1439 - { - yyVAL.str = "extended " - } - case 255: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1445 - { - yyVAL.str = "" - } - case 256: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1449 - { - yyVAL.str = "full " - } - case 257: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1455 - { - yyVAL.str = "" - } - case 258: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1459 - { - yyVAL.str = yyDollar[2].tableIdent.v - } - case 259: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1463 - { - yyVAL.str = yyDollar[2].tableIdent.v - } - case 260: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1469 - { - yyVAL.showFilter = nil - } - case 261: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1473 - { - yyVAL.showFilter = &ShowFilter{Like: string(yyDollar[2].bytes)} - } - case 262: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1477 - { - yyVAL.showFilter = &ShowFilter{Filter: yyDollar[2].expr} - } - case 263: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1483 - { - yyVAL.str = "" - } - case 264: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1487 - { - yyVAL.str = SessionStr - } - case 265: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1491 - { - yyVAL.str = GlobalStr - } - case 266: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1497 - { - yyVAL.statement = &Use{DBName: yyDollar[2].tableIdent} - } - case 267: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1501 - { - yyVAL.statement = &Use{DBName: TableIdent{v: ""}} - } - case 268: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1507 - { - yyVAL.statement = &Begin{} - } - case 269: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1511 - { - yyVAL.statement = &Begin{} - } - case 270: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1517 - { - yyVAL.statement = &Commit{} - } - case 271: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1523 - { - yyVAL.statement = &Rollback{} - } - case 272: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1529 - { - yyVAL.statement = &OtherRead{} - } - case 273: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1533 - { - yyVAL.statement = &OtherRead{} - } - case 274: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1537 - { - yyVAL.statement = &OtherRead{} - } - case 275: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1541 - { - yyVAL.statement = &OtherAdmin{} - } - case 276: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1545 - { - yyVAL.statement = &OtherAdmin{} - } - case 277: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1550 - { - setAllowComments(yylex, true) - } - case 278: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1554 - { - yyVAL.bytes2 = yyDollar[2].bytes2 - setAllowComments(yylex, false) - } - case 279: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1560 - { - yyVAL.bytes2 = nil - } - case 280: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1564 - { - yyVAL.bytes2 = append(yyDollar[1].bytes2, yyDollar[2].bytes) - } - case 281: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1570 - { - yyVAL.str = UnionStr - } - case 282: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1574 - { - yyVAL.str = UnionAllStr - } - case 283: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1578 - { - yyVAL.str = UnionDistinctStr - } - case 284: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1583 - { - yyVAL.str = "" - } - case 285: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1587 - { - yyVAL.str = SQLNoCacheStr - } - case 286: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1591 - { - yyVAL.str = SQLCacheStr - } - case 287: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1596 - { - yyVAL.str = "" - } - case 288: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1600 - { - yyVAL.str = DistinctStr - } - case 289: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1605 - { - yyVAL.str = "" - } - case 290: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1609 - { - yyVAL.str = StraightJoinHint - } - case 291: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1614 - { - yyVAL.selectExprs = nil - } - case 292: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1618 - { - yyVAL.selectExprs = yyDollar[1].selectExprs - } - case 293: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1624 - { - yyVAL.selectExprs = SelectExprs{yyDollar[1].selectExpr} - } - case 294: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1628 - { - yyVAL.selectExprs = append(yyVAL.selectExprs, yyDollar[3].selectExpr) - } - case 295: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1634 - { - yyVAL.selectExpr = &StarExpr{} - } - case 296: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1638 - { - yyVAL.selectExpr = &AliasedExpr{Expr: yyDollar[1].expr, As: yyDollar[2].colIdent} - } - case 297: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1642 - { - yyVAL.selectExpr = &StarExpr{TableName: TableName{Name: yyDollar[1].tableIdent}} - } - case 298: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1646 - { - yyVAL.selectExpr = &StarExpr{TableName: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}} - } - case 299: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1651 - { - yyVAL.colIdent = ColIdent{} - } - case 300: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1655 - { - yyVAL.colIdent = yyDollar[1].colIdent - } - case 301: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1659 - { - yyVAL.colIdent = yyDollar[2].colIdent - } - case 303: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1666 - { - yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) - } - case 304: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1671 - { - yyVAL.tableExprs = TableExprs{&AliasedTableExpr{Expr: TableName{Name: NewTableIdent("dual")}}} - } - case 305: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1675 - { - yyVAL.tableExprs = yyDollar[2].tableExprs - } - case 306: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1681 - { - yyVAL.tableExprs = TableExprs{yyDollar[1].tableExpr} - } - case 307: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1685 - { - yyVAL.tableExprs = append(yyVAL.tableExprs, yyDollar[3].tableExpr) - } - case 310: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1695 - { - yyVAL.tableExpr = yyDollar[1].aliasedTableName - } - case 311: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1699 - { - yyVAL.tableExpr = &AliasedTableExpr{Expr: yyDollar[1].subquery, As: yyDollar[3].tableIdent} - } - case 312: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1703 - { - yyVAL.tableExpr = &ParenTableExpr{Exprs: yyDollar[2].tableExprs} - } - case 313: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1709 - { - yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, As: yyDollar[2].tableIdent, Hints: yyDollar[3].indexHints} - } - case 314: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1713 - { - yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, Partitions: yyDollar[4].partitions, As: yyDollar[6].tableIdent, Hints: yyDollar[7].indexHints} - } - case 315: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1719 - { - yyVAL.columns = Columns{yyDollar[1].colIdent} - } - case 316: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1723 - { - yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) - } - case 317: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1729 - { - yyVAL.partitions = Partitions{yyDollar[1].colIdent} - } - case 318: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1733 - { - yyVAL.partitions = append(yyVAL.partitions, yyDollar[3].colIdent) - } - case 319: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1746 - { - yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} - } - case 320: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1750 - { - yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} - } - case 321: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1754 - { - yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} - } - case 322: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1758 - { - yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr} - } - case 323: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1764 - { - yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} - } - case 324: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1766 - { - yyVAL.joinCondition = JoinCondition{Using: yyDollar[3].columns} - } - case 325: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1770 - { - yyVAL.joinCondition = JoinCondition{} - } - case 326: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1772 - { - yyVAL.joinCondition = yyDollar[1].joinCondition - } - case 327: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1776 - { - yyVAL.joinCondition = JoinCondition{} - } - case 328: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1778 - { - yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} - } - case 329: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1781 - { - yyVAL.empty = struct{}{} - } - case 330: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1783 - { - yyVAL.empty = struct{}{} - } - case 331: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1786 - { - yyVAL.tableIdent = NewTableIdent("") - } - case 332: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1790 - { - yyVAL.tableIdent = yyDollar[1].tableIdent - } - case 333: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1794 - { - yyVAL.tableIdent = yyDollar[2].tableIdent - } - case 335: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1801 - { - yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) - } - case 336: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1807 - { - yyVAL.str = JoinStr - } - case 337: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1811 - { - yyVAL.str = JoinStr - } - case 338: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1815 - { - yyVAL.str = JoinStr - } - case 339: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1821 - { - yyVAL.str = StraightJoinStr - } - case 340: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1827 - { - yyVAL.str = LeftJoinStr - } - case 341: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1831 - { - yyVAL.str = LeftJoinStr - } - case 342: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1835 - { - yyVAL.str = RightJoinStr - } - case 343: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1839 - { - yyVAL.str = RightJoinStr - } - case 344: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1845 - { - yyVAL.str = NaturalJoinStr - } - case 345: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1849 - { - if yyDollar[2].str == LeftJoinStr { - yyVAL.str = NaturalLeftJoinStr - } else { - yyVAL.str = NaturalRightJoinStr - } - } - case 346: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1859 - { - yyVAL.tableName = yyDollar[2].tableName - } - case 347: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1863 - { - yyVAL.tableName = yyDollar[1].tableName - } - case 348: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1869 - { - yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} - } - case 349: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1873 - { - yyVAL.tableName = TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent} - } - case 350: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1878 - { - yyVAL.indexHints = nil - } - case 351: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1882 - { - yyVAL.indexHints = &IndexHints{Type: UseStr, Indexes: yyDollar[4].columns} - } - case 352: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1886 - { - yyVAL.indexHints = &IndexHints{Type: IgnoreStr, Indexes: yyDollar[4].columns} - } - case 353: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1890 - { - yyVAL.indexHints = &IndexHints{Type: ForceStr, Indexes: yyDollar[4].columns} - } - case 354: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1895 - { - yyVAL.expr = nil - } - case 355: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1899 - { - yyVAL.expr = yyDollar[2].expr - } - case 356: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1905 - { - yyVAL.expr = yyDollar[1].expr - } - case 357: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1909 - { - yyVAL.expr = &AndExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} - } - case 358: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1913 - { - yyVAL.expr = &OrExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} - } - case 359: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1917 - { - yyVAL.expr = &NotExpr{Expr: yyDollar[2].expr} - } - case 360: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1921 - { - yyVAL.expr = &IsExpr{Operator: yyDollar[3].str, Expr: yyDollar[1].expr} - } - case 361: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1925 - { - yyVAL.expr = yyDollar[1].expr - } - case 362: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1929 - { - yyVAL.expr = &Default{ColName: yyDollar[2].str} - } - case 363: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1935 - { - yyVAL.str = "" - } - case 364: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1939 - { - yyVAL.str = string(yyDollar[2].bytes) - } - case 365: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1945 - { - yyVAL.boolVal = BoolVal(true) - } - case 366: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1949 - { - yyVAL.boolVal = BoolVal(false) - } - case 367: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1955 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: yyDollar[2].str, Right: yyDollar[3].expr} - } - case 368: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1959 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: InStr, Right: yyDollar[3].colTuple} - } - case 369: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1963 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotInStr, Right: yyDollar[4].colTuple} - } - case 370: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1967 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: LikeStr, Right: yyDollar[3].expr, Escape: yyDollar[4].expr} - } - case 371: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1971 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotLikeStr, Right: yyDollar[4].expr, Escape: yyDollar[5].expr} - } - case 372: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1975 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: RegexpStr, Right: yyDollar[3].expr} - } - case 373: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1979 - { - yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotRegexpStr, Right: yyDollar[4].expr} - } - case 374: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1983 - { - yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: BetweenStr, From: yyDollar[3].expr, To: yyDollar[5].expr} - } - case 375: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1987 - { - yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: NotBetweenStr, From: yyDollar[4].expr, To: yyDollar[6].expr} - } - case 376: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1991 - { - yyVAL.expr = &ExistsExpr{Subquery: yyDollar[2].subquery} - } - case 377: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1997 - { - yyVAL.str = IsNullStr - } - case 378: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2001 - { - yyVAL.str = IsNotNullStr - } - case 379: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2005 - { - yyVAL.str = IsTrueStr - } - case 380: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2009 - { - yyVAL.str = IsNotTrueStr - } - case 381: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2013 - { - yyVAL.str = IsFalseStr - } - case 382: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2017 - { - yyVAL.str = IsNotFalseStr - } - case 383: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2023 - { - yyVAL.str = EqualStr - } - case 384: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2027 - { - yyVAL.str = LessThanStr - } - case 385: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2031 - { - yyVAL.str = GreaterThanStr - } - case 386: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2035 - { - yyVAL.str = LessEqualStr - } - case 387: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2039 - { - yyVAL.str = GreaterEqualStr - } - case 388: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2043 - { - yyVAL.str = NotEqualStr - } - case 389: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2047 - { - yyVAL.str = NullSafeEqualStr - } - case 390: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2052 - { - yyVAL.expr = nil - } - case 391: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2056 - { - yyVAL.expr = yyDollar[2].expr - } - case 392: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2062 - { - yyVAL.colTuple = yyDollar[1].valTuple - } - case 393: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2066 - { - yyVAL.colTuple = yyDollar[1].subquery - } - case 394: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2070 - { - yyVAL.colTuple = ListArg(yyDollar[1].bytes) - } - case 395: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2076 - { - yyVAL.subquery = &Subquery{yyDollar[2].selStmt} - } - case 396: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2082 - { - yyVAL.exprs = Exprs{yyDollar[1].expr} - } - case 397: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2086 - { - yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) - } - case 398: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2092 - { - yyVAL.expr = yyDollar[1].expr - } - case 399: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2096 - { - yyVAL.expr = yyDollar[1].boolVal - } - case 400: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2100 - { - yyVAL.expr = yyDollar[1].colName - } - case 401: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2104 - { - yyVAL.expr = yyDollar[1].expr - } - case 402: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2108 - { - yyVAL.expr = yyDollar[1].subquery - } - case 403: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2112 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitAndStr, Right: yyDollar[3].expr} - } - case 404: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2116 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitOrStr, Right: yyDollar[3].expr} - } - case 405: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2120 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitXorStr, Right: yyDollar[3].expr} - } - case 406: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2124 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: PlusStr, Right: yyDollar[3].expr} - } - case 407: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2128 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MinusStr, Right: yyDollar[3].expr} - } - case 408: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2132 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MultStr, Right: yyDollar[3].expr} - } - case 409: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2136 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: DivStr, Right: yyDollar[3].expr} - } - case 410: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2140 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: IntDivStr, Right: yyDollar[3].expr} - } - case 411: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2144 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} - } - case 412: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2148 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} - } - case 413: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2152 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftLeftStr, Right: yyDollar[3].expr} - } - case 414: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2156 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftRightStr, Right: yyDollar[3].expr} - } - case 415: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2160 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONExtractOp, Right: yyDollar[3].expr} - } - case 416: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2164 - { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONUnquoteExtractOp, Right: yyDollar[3].expr} - } - case 417: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2168 - { - yyVAL.expr = &CollateExpr{Expr: yyDollar[1].expr, Charset: yyDollar[3].str} - } - case 418: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2172 - { - yyVAL.expr = &UnaryExpr{Operator: BinaryStr, Expr: yyDollar[2].expr} - } - case 419: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2176 - { - yyVAL.expr = &UnaryExpr{Operator: UBinaryStr, Expr: yyDollar[2].expr} - } - case 420: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2180 - { - if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { - yyVAL.expr = num - } else { - yyVAL.expr = &UnaryExpr{Operator: UPlusStr, Expr: yyDollar[2].expr} - } - } - case 421: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2188 - { - if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { - // Handle double negative - if num.Val[0] == '-' { - num.Val = num.Val[1:] - yyVAL.expr = num - } else { - yyVAL.expr = NewIntVal(append([]byte("-"), num.Val...)) - } - } else { - yyVAL.expr = &UnaryExpr{Operator: UMinusStr, Expr: yyDollar[2].expr} - } - } - case 422: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2202 - { - yyVAL.expr = &UnaryExpr{Operator: TildaStr, Expr: yyDollar[2].expr} - } - case 423: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2206 - { - yyVAL.expr = &UnaryExpr{Operator: BangStr, Expr: yyDollar[2].expr} - } - case 424: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2210 - { - // This rule prevents the usage of INTERVAL - // as a function. If support is needed for that, - // we'll need to revisit this. The solution - // will be non-trivial because of grammar conflicts. - yyVAL.expr = &IntervalExpr{Expr: yyDollar[2].expr, Unit: yyDollar[3].colIdent.String()} - } - case 429: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2228 - { - yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprs} - } - case 430: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2232 - { - yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprs} - } - case 431: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2236 - { - yyVAL.expr = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprs} - } - case 432: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2246 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprs} - } - case 433: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2250 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprs} - } - case 434: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2254 - { - yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} - } - case 435: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2258 - { - yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} - } - case 436: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2262 - { - yyVAL.expr = &ConvertUsingExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].str} - } - case 437: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2266 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} - } - case 438: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2270 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} - } - case 439: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2274 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} - } - case 440: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2278 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} - } - case 441: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2282 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} - } - case 442: - yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2286 - { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} - } - case 443: - yyDollar = yyS[yypt-9 : yypt+1] - //line sql.y:2290 - { - yyVAL.expr = &MatchExpr{Columns: yyDollar[3].selectExprs, Expr: yyDollar[7].expr, Option: yyDollar[8].str} - } - case 444: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:2294 - { - yyVAL.expr = &GroupConcatExpr{Distinct: yyDollar[3].str, Exprs: yyDollar[4].selectExprs, OrderBy: yyDollar[5].orderBy, Separator: yyDollar[6].str} - } - case 445: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2298 - { - yyVAL.expr = &CaseExpr{Expr: yyDollar[2].expr, Whens: yyDollar[3].whens, Else: yyDollar[4].expr} - } - case 446: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2302 - { - yyVAL.expr = &ValuesFuncExpr{Name: yyDollar[3].colName} - } - case 447: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2312 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_timestamp")} - } - case 448: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2316 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_timestamp")} - } - case 449: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2320 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_time")} - } - case 450: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2324 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} - } - case 451: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2329 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} - } - case 452: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2334 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} - } - case 453: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2339 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} - } - case 454: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2344 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} - } - case 457: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2358 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprs} - } - case 458: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2362 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprs} - } - case 459: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2366 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprs} - } - case 460: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2370 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprs} - } - case 461: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2376 - { - yyVAL.str = "" - } - case 462: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2380 - { - yyVAL.str = BooleanModeStr - } - case 463: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2384 - { - yyVAL.str = NaturalLanguageModeStr - } - case 464: - yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:2388 - { - yyVAL.str = NaturalLanguageModeWithQueryExpansionStr - } - case 465: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2392 - { - yyVAL.str = QueryExpansionStr - } - case 466: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2398 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 467: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2402 - { - yyVAL.str = string(yyDollar[1].bytes) - } - case 468: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2408 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 469: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2412 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} - } - case 470: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2416 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: string(yyDollar[3].bytes)} - } - case 471: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2420 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 472: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2424 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 473: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2428 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - yyVAL.convertType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.convertType.Scale = yyDollar[2].LengthScaleOption.Scale - } - case 474: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2434 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 475: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2438 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 476: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2442 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 477: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2446 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 478: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2450 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} - } - case 479: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2454 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 480: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2458 - { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} - } - case 481: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2463 - { - yyVAL.expr = nil - } - case 482: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2467 - { - yyVAL.expr = yyDollar[1].expr - } - case 483: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2472 - { - yyVAL.str = string("") - } - case 484: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2476 - { - yyVAL.str = " separator '" + string(yyDollar[2].bytes) + "'" - } - case 485: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2482 - { - yyVAL.whens = []*When{yyDollar[1].when} - } - case 486: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2486 - { - yyVAL.whens = append(yyDollar[1].whens, yyDollar[2].when) - } - case 487: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2492 - { - yyVAL.when = &When{Cond: yyDollar[2].expr, Val: yyDollar[4].expr} - } - case 488: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2497 - { - yyVAL.expr = nil - } - case 489: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2501 - { - yyVAL.expr = yyDollar[2].expr - } - case 490: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2507 - { - yyVAL.colName = &ColName{Name: yyDollar[1].colIdent} - } - case 491: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2511 - { - yyVAL.colName = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} - } - case 492: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2515 - { - yyVAL.colName = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} - } - case 493: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2521 - { - yyVAL.expr = NewStrVal(yyDollar[1].bytes) - } - case 494: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2525 - { - yyVAL.expr = NewHexVal(yyDollar[1].bytes) - } - case 495: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2529 - { - yyVAL.expr = NewBitVal(yyDollar[1].bytes) - } - case 496: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2533 - { - yyVAL.expr = NewIntVal(yyDollar[1].bytes) - } - case 497: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2537 - { - yyVAL.expr = NewFloatVal(yyDollar[1].bytes) - } - case 498: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2541 - { - yyVAL.expr = NewHexNum(yyDollar[1].bytes) - } - case 499: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2545 - { - yyVAL.expr = NewValArg(yyDollar[1].bytes) - } - case 500: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2549 - { - yyVAL.expr = &NullVal{} - } - case 501: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2555 - { - // TODO(sougou): Deprecate this construct. - if yyDollar[1].colIdent.Lowered() != "value" { - yylex.Error("expecting value after next") - return 1 - } - yyVAL.expr = NewIntVal([]byte("1")) - } - case 502: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2564 - { - yyVAL.expr = NewIntVal(yyDollar[1].bytes) - } - case 503: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2568 - { - yyVAL.expr = NewValArg(yyDollar[1].bytes) - } - case 504: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2573 - { - yyVAL.exprs = nil - } - case 505: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2577 - { - yyVAL.exprs = yyDollar[3].exprs - } - case 506: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2582 - { - yyVAL.expr = nil - } - case 507: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2586 - { - yyVAL.expr = yyDollar[2].expr - } - case 508: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2591 - { - yyVAL.orderBy = nil - } - case 509: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2595 - { - yyVAL.orderBy = yyDollar[3].orderBy - } - case 510: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2601 - { - yyVAL.orderBy = OrderBy{yyDollar[1].order} - } - case 511: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2605 - { - yyVAL.orderBy = append(yyDollar[1].orderBy, yyDollar[3].order) - } - case 512: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2611 - { - yyVAL.order = &Order{Expr: yyDollar[1].expr, Direction: yyDollar[2].str} - } - case 513: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2616 - { - yyVAL.str = AscScr - } - case 514: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2620 - { - yyVAL.str = AscScr - } - case 515: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2624 - { - yyVAL.str = DescScr - } - case 516: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2629 - { - yyVAL.limit = nil - } - case 517: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2633 - { - yyVAL.limit = &Limit{Rowcount: yyDollar[2].expr} - } - case 518: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2637 - { - yyVAL.limit = &Limit{Offset: yyDollar[2].expr, Rowcount: yyDollar[4].expr} - } - case 519: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2641 - { - yyVAL.limit = &Limit{Offset: yyDollar[4].expr, Rowcount: yyDollar[2].expr} - } - case 520: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2646 - { - yyVAL.str = "" - } - case 521: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2650 - { - yyVAL.str = ForUpdateStr - } - case 522: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2654 - { - yyVAL.str = ShareModeStr - } - case 523: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2667 - { - yyVAL.ins = &Insert{Rows: yyDollar[2].values} - } - case 524: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2671 - { - yyVAL.ins = &Insert{Rows: yyDollar[1].selStmt} - } - case 525: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2675 - { - // Drop the redundant parenthesis. - yyVAL.ins = &Insert{Rows: yyDollar[2].selStmt} - } - case 526: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2680 - { - yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].values} - } - case 527: - yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2684 - { - yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[4].selStmt} - } - case 528: - yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2688 - { - // Drop the redundant parenthesis. - yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].selStmt} - } - case 529: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2695 - { - yyVAL.columns = Columns{yyDollar[1].colIdent} - } - case 530: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2699 - { - yyVAL.columns = Columns{yyDollar[3].colIdent} - } - case 531: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2703 - { - yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) - } - case 532: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2707 - { - yyVAL.columns = append(yyVAL.columns, yyDollar[5].colIdent) - } - case 533: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2712 - { - yyVAL.updateExprs = nil - } - case 534: - yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2716 - { - yyVAL.updateExprs = yyDollar[5].updateExprs - } - case 535: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2722 - { - yyVAL.values = Values{yyDollar[1].valTuple} - } - case 536: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2726 - { - yyVAL.values = append(yyDollar[1].values, yyDollar[3].valTuple) - } - case 537: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2732 - { - yyVAL.valTuple = yyDollar[1].valTuple - } - case 538: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2736 - { - yyVAL.valTuple = ValTuple{} - } - case 539: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2742 - { - yyVAL.valTuple = ValTuple(yyDollar[2].exprs) - } - case 540: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2748 - { - if len(yyDollar[1].valTuple) == 1 { - yyVAL.expr = &ParenExpr{yyDollar[1].valTuple[0]} - } else { - yyVAL.expr = yyDollar[1].valTuple - } - } - case 541: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2758 - { - yyVAL.updateExprs = UpdateExprs{yyDollar[1].updateExpr} - } - case 542: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2762 - { - yyVAL.updateExprs = append(yyDollar[1].updateExprs, yyDollar[3].updateExpr) - } - case 543: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2768 - { - yyVAL.updateExpr = &UpdateExpr{Name: yyDollar[1].colName, Expr: yyDollar[3].expr} - } - case 544: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2774 - { - yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} - } - case 545: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2778 - { - yyVAL.setExprs = append(yyDollar[1].setExprs, yyDollar[3].setExpr) - } - case 546: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2784 - { - yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("on"))} - } - case 547: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2788 - { - yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: yyDollar[3].expr} - } - case 548: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2792 - { - yyVAL.setExpr = &SetExpr{Name: NewColIdent(string(yyDollar[1].bytes)), Expr: yyDollar[2].expr} - } - case 550: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2799 - { - yyVAL.bytes = []byte("charset") - } - case 552: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2806 - { - yyVAL.expr = NewStrVal([]byte(yyDollar[1].colIdent.String())) - } - case 553: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2810 - { - yyVAL.expr = NewStrVal(yyDollar[1].bytes) - } - case 554: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2814 - { - yyVAL.expr = &Default{} - } - case 557: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2823 - { - yyVAL.byt = 0 - } - case 558: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2825 - { - yyVAL.byt = 1 - } - case 559: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2828 - { - yyVAL.empty = struct{}{} - } - case 560: - yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2830 - { - yyVAL.empty = struct{}{} - } - case 561: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2833 - { - yyVAL.str = "" - } - case 562: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2835 - { - yyVAL.str = IgnoreStr - } - case 563: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2839 - { - yyVAL.empty = struct{}{} - } - case 564: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2841 - { - yyVAL.empty = struct{}{} - } - case 565: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2843 - { - yyVAL.empty = struct{}{} - } - case 566: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2845 - { - yyVAL.empty = struct{}{} - } - case 567: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2847 - { - yyVAL.empty = struct{}{} - } - case 568: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2849 - { - yyVAL.empty = struct{}{} - } - case 569: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2851 - { - yyVAL.empty = struct{}{} - } - case 570: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2853 - { - yyVAL.empty = struct{}{} - } - case 571: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2855 - { - yyVAL.empty = struct{}{} - } - case 572: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2857 - { - yyVAL.empty = struct{}{} - } - case 573: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2860 - { - yyVAL.empty = struct{}{} - } - case 574: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2862 - { - yyVAL.empty = struct{}{} - } - case 575: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2864 - { - yyVAL.empty = struct{}{} - } - case 576: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2868 - { - yyVAL.empty = struct{}{} - } - case 577: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2870 - { - yyVAL.empty = struct{}{} - } - case 578: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2873 - { - yyVAL.empty = struct{}{} - } - case 579: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2875 - { - yyVAL.empty = struct{}{} - } - case 580: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2877 - { - yyVAL.empty = struct{}{} - } - case 581: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2880 - { - yyVAL.colIdent = ColIdent{} - } - case 582: - yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2882 - { - yyVAL.colIdent = yyDollar[2].colIdent - } - case 583: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2886 - { - yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) - } - case 584: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2890 - { - yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) - } - case 586: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2897 - { - yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) - } - case 587: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2903 - { - yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) - } - case 588: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2907 - { - yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) - } - case 590: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2914 - { - yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) - } - case 781: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3130 - { - if incNesting(yylex) { - yylex.Error("max nesting level reached") - return 1 - } - } - case 782: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3139 - { - decNesting(yylex) - } - case 783: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:3144 - { - forceEOF(yylex) - } - case 784: - yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:3149 - { - forceEOF(yylex) - } - case 785: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3153 - { - forceEOF(yylex) - } - case 786: - yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3157 - { - forceEOF(yylex) - } - } - goto yystack /* stack new state and value */ -} diff --git a/vendor/github.com/xwb1989/sqlparser/sql.y b/vendor/github.com/xwb1989/sqlparser/sql.y deleted file mode 100644 index efbb794ca..000000000 --- a/vendor/github.com/xwb1989/sqlparser/sql.y +++ /dev/null @@ -1,3159 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -%{ -package sqlparser - -func setParseTree(yylex interface{}, stmt Statement) { - yylex.(*Tokenizer).ParseTree = stmt -} - -func setAllowComments(yylex interface{}, allow bool) { - yylex.(*Tokenizer).AllowComments = allow -} - -func setDDL(yylex interface{}, ddl *DDL) { - yylex.(*Tokenizer).partialDDL = ddl -} - -func incNesting(yylex interface{}) bool { - yylex.(*Tokenizer).nesting++ - if yylex.(*Tokenizer).nesting == 200 { - return true - } - return false -} - -func decNesting(yylex interface{}) { - yylex.(*Tokenizer).nesting-- -} - -// forceEOF forces the lexer to end prematurely. Not all SQL statements -// are supported by the Parser, thus calling forceEOF will make the lexer -// return EOF early. -func forceEOF(yylex interface{}) { - yylex.(*Tokenizer).ForceEOF = true -} - -%} - -%union { - empty struct{} - statement Statement - selStmt SelectStatement - ddl *DDL - ins *Insert - byt byte - bytes []byte - bytes2 [][]byte - str string - strs []string - selectExprs SelectExprs - selectExpr SelectExpr - columns Columns - partitions Partitions - colName *ColName - tableExprs TableExprs - tableExpr TableExpr - joinCondition JoinCondition - tableName TableName - tableNames TableNames - indexHints *IndexHints - expr Expr - exprs Exprs - boolVal BoolVal - colTuple ColTuple - values Values - valTuple ValTuple - subquery *Subquery - whens []*When - when *When - orderBy OrderBy - order *Order - limit *Limit - updateExprs UpdateExprs - setExprs SetExprs - updateExpr *UpdateExpr - setExpr *SetExpr - colIdent ColIdent - tableIdent TableIdent - convertType *ConvertType - aliasedTableName *AliasedTableExpr - TableSpec *TableSpec - columnType ColumnType - colKeyOpt ColumnKeyOption - optVal *SQLVal - LengthScaleOption LengthScaleOption - columnDefinition *ColumnDefinition - indexDefinition *IndexDefinition - indexInfo *IndexInfo - indexOption *IndexOption - indexOptions []*IndexOption - indexColumn *IndexColumn - indexColumns []*IndexColumn - partDefs []*PartitionDefinition - partDef *PartitionDefinition - partSpec *PartitionSpec - vindexParam VindexParam - vindexParams []VindexParam - showFilter *ShowFilter -} - -%token LEX_ERROR -%left UNION -%token SELECT STREAM INSERT UPDATE DELETE FROM WHERE GROUP HAVING ORDER BY LIMIT OFFSET FOR -%token ALL DISTINCT AS EXISTS ASC DESC INTO DUPLICATE KEY DEFAULT SET LOCK KEYS -%token VALUES LAST_INSERT_ID -%token NEXT VALUE SHARE MODE -%token SQL_NO_CACHE SQL_CACHE -%left JOIN STRAIGHT_JOIN LEFT RIGHT INNER OUTER CROSS NATURAL USE FORCE -%left ON USING -%token '(' ',' ')' -%token ID HEX STRING INTEGRAL FLOAT HEXNUM VALUE_ARG LIST_ARG COMMENT COMMENT_KEYWORD BIT_LITERAL -%token NULL TRUE FALSE - -// Precedence dictated by mysql. But the vitess grammar is simplified. -// Some of these operators don't conflict in our situation. Nevertheless, -// it's better to have these listed in the correct order. Also, we don't -// support all operators yet. -%left OR -%left AND -%right NOT '!' -%left BETWEEN CASE WHEN THEN ELSE END -%left '=' '<' '>' LE GE NE NULL_SAFE_EQUAL IS LIKE REGEXP IN -%left '|' -%left '&' -%left SHIFT_LEFT SHIFT_RIGHT -%left '+' '-' -%left '*' '/' DIV '%' MOD -%left '^' -%right '~' UNARY -%left COLLATE -%right BINARY UNDERSCORE_BINARY -%right INTERVAL -%nonassoc '.' - -// There is no need to define precedence for the JSON -// operators because the syntax is restricted enough that -// they don't cause conflicts. -%token JSON_EXTRACT_OP JSON_UNQUOTE_EXTRACT_OP - -// DDL Tokens -%token CREATE ALTER DROP RENAME ANALYZE ADD -%token SCHEMA TABLE INDEX VIEW TO IGNORE IF UNIQUE PRIMARY COLUMN CONSTRAINT SPATIAL FULLTEXT FOREIGN KEY_BLOCK_SIZE -%token SHOW DESCRIBE EXPLAIN DATE ESCAPE REPAIR OPTIMIZE TRUNCATE -%token MAXVALUE PARTITION REORGANIZE LESS THAN PROCEDURE TRIGGER -%token VINDEX VINDEXES -%token STATUS VARIABLES - -// Transaction Tokens -%token BEGIN START TRANSACTION COMMIT ROLLBACK - -// Type Tokens -%token BIT TINYINT SMALLINT MEDIUMINT INT INTEGER BIGINT INTNUM -%token REAL DOUBLE FLOAT_TYPE DECIMAL NUMERIC -%token TIME TIMESTAMP DATETIME YEAR -%token CHAR VARCHAR BOOL CHARACTER VARBINARY NCHAR -%token TEXT TINYTEXT MEDIUMTEXT LONGTEXT -%token BLOB TINYBLOB MEDIUMBLOB LONGBLOB JSON ENUM -%token GEOMETRY POINT LINESTRING POLYGON GEOMETRYCOLLECTION MULTIPOINT MULTILINESTRING MULTIPOLYGON - -// Type Modifiers -%token NULLX AUTO_INCREMENT APPROXNUM SIGNED UNSIGNED ZEROFILL - -// Supported SHOW tokens -%token DATABASES TABLES VITESS_KEYSPACES VITESS_SHARDS VITESS_TABLETS VSCHEMA_TABLES EXTENDED FULL PROCESSLIST - -// SET tokens -%token NAMES CHARSET GLOBAL SESSION ISOLATION LEVEL READ WRITE ONLY REPEATABLE COMMITTED UNCOMMITTED SERIALIZABLE - -// Functions -%token CURRENT_TIMESTAMP DATABASE CURRENT_DATE -%token CURRENT_TIME LOCALTIME LOCALTIMESTAMP -%token UTC_DATE UTC_TIME UTC_TIMESTAMP -%token REPLACE -%token CONVERT CAST -%token SUBSTR SUBSTRING -%token GROUP_CONCAT SEPARATOR - -// Match -%token MATCH AGAINST BOOLEAN LANGUAGE WITH QUERY EXPANSION - -// MySQL reserved words that are unused by this grammar will map to this token. -%token UNUSED - -%type command -%type select_statement base_select union_lhs union_rhs -%type stream_statement insert_statement update_statement delete_statement set_statement -%type create_statement alter_statement rename_statement drop_statement truncate_statement -%type create_table_prefix -%type analyze_statement show_statement use_statement other_statement -%type begin_statement commit_statement rollback_statement -%type comment_opt comment_list -%type union_op insert_or_replace -%type distinct_opt straight_join_opt cache_opt match_option separator_opt -%type like_escape_opt -%type select_expression_list select_expression_list_opt -%type select_expression -%type expression -%type from_opt table_references -%type table_reference table_factor join_table -%type join_condition join_condition_opt on_expression_opt -%type table_name_list -%type inner_join outer_join straight_join natural_join -%type table_name into_table_name -%type aliased_table_name -%type index_hint_list -%type where_expression_opt -%type condition -%type boolean_value -%type compare -%type insert_data -%type value value_expression num_val -%type function_call_keyword function_call_nonkeyword function_call_generic function_call_conflict -%type is_suffix -%type col_tuple -%type expression_list -%type tuple_list -%type row_tuple tuple_or_empty -%type tuple_expression -%type subquery -%type column_name -%type when_expression_list -%type when_expression -%type expression_opt else_expression_opt -%type group_by_opt -%type having_opt -%type order_by_opt order_list -%type order -%type asc_desc_opt -%type limit_opt -%type lock_opt -%type ins_column_list column_list -%type opt_partition_clause partition_list -%type on_dup_opt -%type update_list -%type set_list transaction_chars -%type charset_or_character_set -%type update_expression -%type set_expression transaction_char isolation_level -%type for_from -%type ignore_opt default_opt -%type extended_opt full_opt from_database_opt tables_or_processlist -%type like_or_where_opt -%type exists_opt -%type not_exists_opt non_add_drop_or_rename_operation to_opt index_opt constraint_opt -%type reserved_keyword non_reserved_keyword -%type sql_id reserved_sql_id col_alias as_ci_opt using_opt -%type charset_value -%type table_id reserved_table_id table_alias as_opt_id -%type as_opt -%type force_eof ddl_force_eof -%type charset -%type set_session_or_global show_session_or_global -%type convert_type -%type column_type -%type int_type decimal_type numeric_type time_type char_type spatial_type -%type length_opt column_default_opt column_comment_opt on_update_opt -%type charset_opt collate_opt -%type unsigned_opt zero_fill_opt -%type float_length_opt decimal_length_opt -%type null_opt auto_increment_opt -%type column_key_opt -%type enum_values -%type column_definition -%type index_definition -%type index_or_key -%type equal_opt -%type table_spec table_column_list -%type table_option_list table_option table_opt_value -%type index_info -%type index_column -%type index_column_list -%type index_option -%type index_option_list -%type partition_definitions -%type partition_definition -%type partition_operation -%type vindex_param -%type vindex_param_list vindex_params_opt -%type vindex_type vindex_type_opt -%type alter_object_type - -%start any_command - -%% - -any_command: - command semicolon_opt - { - setParseTree(yylex, $1) - } - -semicolon_opt: -/*empty*/ {} -| ';' {} - -command: - select_statement - { - $$ = $1 - } -| stream_statement -| insert_statement -| update_statement -| delete_statement -| set_statement -| create_statement -| alter_statement -| rename_statement -| drop_statement -| truncate_statement -| analyze_statement -| show_statement -| use_statement -| begin_statement -| commit_statement -| rollback_statement -| other_statement - -select_statement: - base_select order_by_opt limit_opt lock_opt - { - sel := $1.(*Select) - sel.OrderBy = $2 - sel.Limit = $3 - sel.Lock = $4 - $$ = sel - } -| union_lhs union_op union_rhs order_by_opt limit_opt lock_opt - { - $$ = &Union{Type: $2, Left: $1, Right: $3, OrderBy: $4, Limit: $5, Lock: $6} - } -| SELECT comment_opt cache_opt NEXT num_val for_from table_name - { - $$ = &Select{Comments: Comments($2), Cache: $3, SelectExprs: SelectExprs{Nextval{Expr: $5}}, From: TableExprs{&AliasedTableExpr{Expr: $7}}} - } - -stream_statement: - STREAM comment_opt select_expression FROM table_name - { - $$ = &Stream{Comments: Comments($2), SelectExpr: $3, Table: $5} - } - -// base_select is an unparenthesized SELECT with no order by clause or beyond. -base_select: - SELECT comment_opt cache_opt distinct_opt straight_join_opt select_expression_list from_opt where_expression_opt group_by_opt having_opt - { - $$ = &Select{Comments: Comments($2), Cache: $3, Distinct: $4, Hints: $5, SelectExprs: $6, From: $7, Where: NewWhere(WhereStr, $8), GroupBy: GroupBy($9), Having: NewWhere(HavingStr, $10)} - } - -union_lhs: - select_statement - { - $$ = $1 - } -| openb select_statement closeb - { - $$ = &ParenSelect{Select: $2} - } - -union_rhs: - base_select - { - $$ = $1 - } -| openb select_statement closeb - { - $$ = &ParenSelect{Select: $2} - } - - -insert_statement: - insert_or_replace comment_opt ignore_opt into_table_name opt_partition_clause insert_data on_dup_opt - { - // insert_data returns a *Insert pre-filled with Columns & Values - ins := $6 - ins.Action = $1 - ins.Comments = $2 - ins.Ignore = $3 - ins.Table = $4 - ins.Partitions = $5 - ins.OnDup = OnDup($7) - $$ = ins - } -| insert_or_replace comment_opt ignore_opt into_table_name opt_partition_clause SET update_list on_dup_opt - { - cols := make(Columns, 0, len($7)) - vals := make(ValTuple, 0, len($8)) - for _, updateList := range $7 { - cols = append(cols, updateList.Name.Name) - vals = append(vals, updateList.Expr) - } - $$ = &Insert{Action: $1, Comments: Comments($2), Ignore: $3, Table: $4, Partitions: $5, Columns: cols, Rows: Values{vals}, OnDup: OnDup($8)} - } - -insert_or_replace: - INSERT - { - $$ = InsertStr - } -| REPLACE - { - $$ = ReplaceStr - } - -update_statement: - UPDATE comment_opt table_references SET update_list where_expression_opt order_by_opt limit_opt - { - $$ = &Update{Comments: Comments($2), TableExprs: $3, Exprs: $5, Where: NewWhere(WhereStr, $6), OrderBy: $7, Limit: $8} - } - -delete_statement: - DELETE comment_opt FROM table_name opt_partition_clause where_expression_opt order_by_opt limit_opt - { - $$ = &Delete{Comments: Comments($2), TableExprs: TableExprs{&AliasedTableExpr{Expr:$4}}, Partitions: $5, Where: NewWhere(WhereStr, $6), OrderBy: $7, Limit: $8} - } -| DELETE comment_opt FROM table_name_list USING table_references where_expression_opt - { - $$ = &Delete{Comments: Comments($2), Targets: $4, TableExprs: $6, Where: NewWhere(WhereStr, $7)} - } -| DELETE comment_opt table_name_list from_or_using table_references where_expression_opt - { - $$ = &Delete{Comments: Comments($2), Targets: $3, TableExprs: $5, Where: NewWhere(WhereStr, $6)} - } - -from_or_using: - FROM {} -| USING {} - -table_name_list: - table_name - { - $$ = TableNames{$1} - } -| table_name_list ',' table_name - { - $$ = append($$, $3) - } - -opt_partition_clause: - { - $$ = nil - } -| PARTITION openb partition_list closeb - { - $$ = $3 - } - -set_statement: - SET comment_opt set_list - { - $$ = &Set{Comments: Comments($2), Exprs: $3} - } -| SET comment_opt set_session_or_global set_list - { - $$ = &Set{Comments: Comments($2), Scope: $3, Exprs: $4} - } -| SET comment_opt set_session_or_global TRANSACTION transaction_chars - { - $$ = &Set{Comments: Comments($2), Scope: $3, Exprs: $5} - } -| SET comment_opt TRANSACTION transaction_chars - { - $$ = &Set{Comments: Comments($2), Exprs: $4} - } - -transaction_chars: - transaction_char - { - $$ = SetExprs{$1} - } -| transaction_chars ',' transaction_char - { - $$ = append($$, $3) - } - -transaction_char: - ISOLATION LEVEL isolation_level - { - $$ = $3 - } -| READ WRITE - { - $$ = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("0"))} - } -| READ ONLY - { - $$ = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("1"))} - } - -isolation_level: - REPEATABLE READ - { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("repeatable read"))} - } -| READ COMMITTED - { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read committed"))} - } -| READ UNCOMMITTED - { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read uncommitted"))} - } -| SERIALIZABLE - { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("serializable"))} - } - -set_session_or_global: - SESSION - { - $$ = SessionStr - } -| GLOBAL - { - $$ = GlobalStr - } - -create_statement: - create_table_prefix table_spec - { - $1.TableSpec = $2 - $$ = $1 - } -| CREATE constraint_opt INDEX ID using_opt ON table_name ddl_force_eof - { - // Change this to an alter statement - $$ = &DDL{Action: AlterStr, Table: $7, NewName:$7} - } -| CREATE VIEW table_name ddl_force_eof - { - $$ = &DDL{Action: CreateStr, NewName: $3.ToViewName()} - } -| CREATE OR REPLACE VIEW table_name ddl_force_eof - { - $$ = &DDL{Action: CreateStr, NewName: $5.ToViewName()} - } -| CREATE VINDEX sql_id vindex_type_opt vindex_params_opt - { - $$ = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{ - Name: $3, - Type: $4, - Params: $5, - }} - } -| CREATE DATABASE not_exists_opt ID ddl_force_eof - { - $$ = &DBDDL{Action: CreateStr, DBName: string($4)} - } -| CREATE SCHEMA not_exists_opt ID ddl_force_eof - { - $$ = &DBDDL{Action: CreateStr, DBName: string($4)} - } - -vindex_type_opt: - { - $$ = NewColIdent("") - } -| USING vindex_type - { - $$ = $2 - } - -vindex_type: - ID - { - $$ = NewColIdent(string($1)) - } - -vindex_params_opt: - { - var v []VindexParam - $$ = v - } -| WITH vindex_param_list - { - $$ = $2 - } - -vindex_param_list: - vindex_param - { - $$ = make([]VindexParam, 0, 4) - $$ = append($$, $1) - } -| vindex_param_list ',' vindex_param - { - $$ = append($$, $3) - } - -vindex_param: - reserved_sql_id '=' table_opt_value - { - $$ = VindexParam{Key: $1, Val: $3} - } - -create_table_prefix: - CREATE TABLE not_exists_opt table_name - { - $$ = &DDL{Action: CreateStr, NewName: $4} - setDDL(yylex, $$) - } - -table_spec: - '(' table_column_list ')' table_option_list - { - $$ = $2 - $$.Options = $4 - } - -table_column_list: - column_definition - { - $$ = &TableSpec{} - $$.AddColumn($1) - } -| table_column_list ',' column_definition - { - $$.AddColumn($3) - } -| table_column_list ',' index_definition - { - $$.AddIndex($3) - } - -column_definition: - ID column_type null_opt column_default_opt on_update_opt auto_increment_opt column_key_opt column_comment_opt - { - $2.NotNull = $3 - $2.Default = $4 - $2.OnUpdate = $5 - $2.Autoincrement = $6 - $2.KeyOpt = $7 - $2.Comment = $8 - $$ = &ColumnDefinition{Name: NewColIdent(string($1)), Type: $2} - } -column_type: - numeric_type unsigned_opt zero_fill_opt - { - $$ = $1 - $$.Unsigned = $2 - $$.Zerofill = $3 - } -| char_type -| time_type -| spatial_type - -numeric_type: - int_type length_opt - { - $$ = $1 - $$.Length = $2 - } -| decimal_type - { - $$ = $1 - } - -int_type: - BIT - { - $$ = ColumnType{Type: string($1)} - } -| TINYINT - { - $$ = ColumnType{Type: string($1)} - } -| SMALLINT - { - $$ = ColumnType{Type: string($1)} - } -| MEDIUMINT - { - $$ = ColumnType{Type: string($1)} - } -| INT - { - $$ = ColumnType{Type: string($1)} - } -| INTEGER - { - $$ = ColumnType{Type: string($1)} - } -| BIGINT - { - $$ = ColumnType{Type: string($1)} - } - -decimal_type: -REAL float_length_opt - { - $$ = ColumnType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } -| DOUBLE float_length_opt - { - $$ = ColumnType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } -| FLOAT_TYPE float_length_opt - { - $$ = ColumnType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } -| DECIMAL decimal_length_opt - { - $$ = ColumnType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } -| NUMERIC decimal_length_opt - { - $$ = ColumnType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } - -time_type: - DATE - { - $$ = ColumnType{Type: string($1)} - } -| TIME length_opt - { - $$ = ColumnType{Type: string($1), Length: $2} - } -| TIMESTAMP length_opt - { - $$ = ColumnType{Type: string($1), Length: $2} - } -| DATETIME length_opt - { - $$ = ColumnType{Type: string($1), Length: $2} - } -| YEAR - { - $$ = ColumnType{Type: string($1)} - } - -char_type: - CHAR length_opt charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Length: $2, Charset: $3, Collate: $4} - } -| VARCHAR length_opt charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Length: $2, Charset: $3, Collate: $4} - } -| BINARY length_opt - { - $$ = ColumnType{Type: string($1), Length: $2} - } -| VARBINARY length_opt - { - $$ = ColumnType{Type: string($1), Length: $2} - } -| TEXT charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3} - } -| TINYTEXT charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3} - } -| MEDIUMTEXT charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3} - } -| LONGTEXT charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3} - } -| BLOB - { - $$ = ColumnType{Type: string($1)} - } -| TINYBLOB - { - $$ = ColumnType{Type: string($1)} - } -| MEDIUMBLOB - { - $$ = ColumnType{Type: string($1)} - } -| LONGBLOB - { - $$ = ColumnType{Type: string($1)} - } -| JSON - { - $$ = ColumnType{Type: string($1)} - } -| ENUM '(' enum_values ')' charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), EnumValues: $3, Charset: $5, Collate: $6} - } -// need set_values / SetValues ? -| SET '(' enum_values ')' charset_opt collate_opt - { - $$ = ColumnType{Type: string($1), EnumValues: $3, Charset: $5, Collate: $6} - } - -spatial_type: - GEOMETRY - { - $$ = ColumnType{Type: string($1)} - } -| POINT - { - $$ = ColumnType{Type: string($1)} - } -| LINESTRING - { - $$ = ColumnType{Type: string($1)} - } -| POLYGON - { - $$ = ColumnType{Type: string($1)} - } -| GEOMETRYCOLLECTION - { - $$ = ColumnType{Type: string($1)} - } -| MULTIPOINT - { - $$ = ColumnType{Type: string($1)} - } -| MULTILINESTRING - { - $$ = ColumnType{Type: string($1)} - } -| MULTIPOLYGON - { - $$ = ColumnType{Type: string($1)} - } - -enum_values: - STRING - { - $$ = make([]string, 0, 4) - $$ = append($$, "'" + string($1) + "'") - } -| enum_values ',' STRING - { - $$ = append($1, "'" + string($3) + "'") - } - -length_opt: - { - $$ = nil - } -| '(' INTEGRAL ')' - { - $$ = NewIntVal($2) - } - -float_length_opt: - { - $$ = LengthScaleOption{} - } -| '(' INTEGRAL ',' INTEGRAL ')' - { - $$ = LengthScaleOption{ - Length: NewIntVal($2), - Scale: NewIntVal($4), - } - } - -decimal_length_opt: - { - $$ = LengthScaleOption{} - } -| '(' INTEGRAL ')' - { - $$ = LengthScaleOption{ - Length: NewIntVal($2), - } - } -| '(' INTEGRAL ',' INTEGRAL ')' - { - $$ = LengthScaleOption{ - Length: NewIntVal($2), - Scale: NewIntVal($4), - } - } - -unsigned_opt: - { - $$ = BoolVal(false) - } -| UNSIGNED - { - $$ = BoolVal(true) - } - -zero_fill_opt: - { - $$ = BoolVal(false) - } -| ZEROFILL - { - $$ = BoolVal(true) - } - -// Null opt returns false to mean NULL (i.e. the default) and true for NOT NULL -null_opt: - { - $$ = BoolVal(false) - } -| NULL - { - $$ = BoolVal(false) - } -| NOT NULL - { - $$ = BoolVal(true) - } - -column_default_opt: - { - $$ = nil - } -| DEFAULT STRING - { - $$ = NewStrVal($2) - } -| DEFAULT INTEGRAL - { - $$ = NewIntVal($2) - } -| DEFAULT FLOAT - { - $$ = NewFloatVal($2) - } -| DEFAULT NULL - { - $$ = NewValArg($2) - } -| DEFAULT CURRENT_TIMESTAMP - { - $$ = NewValArg($2) - } -| DEFAULT BIT_LITERAL - { - $$ = NewBitVal($2) - } - -on_update_opt: - { - $$ = nil - } -| ON UPDATE CURRENT_TIMESTAMP -{ - $$ = NewValArg($3) -} - -auto_increment_opt: - { - $$ = BoolVal(false) - } -| AUTO_INCREMENT - { - $$ = BoolVal(true) - } - -charset_opt: - { - $$ = "" - } -| CHARACTER SET ID - { - $$ = string($3) - } -| CHARACTER SET BINARY - { - $$ = string($3) - } - -collate_opt: - { - $$ = "" - } -| COLLATE ID - { - $$ = string($2) - } - -column_key_opt: - { - $$ = colKeyNone - } -| PRIMARY KEY - { - $$ = colKeyPrimary - } -| KEY - { - $$ = colKey - } -| UNIQUE KEY - { - $$ = colKeyUniqueKey - } -| UNIQUE - { - $$ = colKeyUnique - } - -column_comment_opt: - { - $$ = nil - } -| COMMENT_KEYWORD STRING - { - $$ = NewStrVal($2) - } - -index_definition: - index_info '(' index_column_list ')' index_option_list - { - $$ = &IndexDefinition{Info: $1, Columns: $3, Options: $5} - } -| index_info '(' index_column_list ')' - { - $$ = &IndexDefinition{Info: $1, Columns: $3} - } - -index_option_list: - index_option - { - $$ = []*IndexOption{$1} - } -| index_option_list index_option - { - $$ = append($$, $2) - } - -index_option: - USING ID - { - $$ = &IndexOption{Name: string($1), Using: string($2)} - } -| KEY_BLOCK_SIZE equal_opt INTEGRAL - { - // should not be string - $$ = &IndexOption{Name: string($1), Value: NewIntVal($3)} - } -| COMMENT_KEYWORD STRING - { - $$ = &IndexOption{Name: string($1), Value: NewStrVal($2)} - } - -equal_opt: - /* empty */ - { - $$ = "" - } -| '=' - { - $$ = string($1) - } - -index_info: - PRIMARY KEY - { - $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} - } -| SPATIAL index_or_key ID - { - $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent(string($3)), Spatial: true, Unique: false} - } -| UNIQUE index_or_key ID - { - $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent(string($3)), Unique: true} - } -| UNIQUE ID - { - $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: true} - } -| index_or_key ID - { - $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: false} - } - -index_or_key: - INDEX - { - $$ = string($1) - } - | KEY - { - $$ = string($1) - } - -index_column_list: - index_column - { - $$ = []*IndexColumn{$1} - } -| index_column_list ',' index_column - { - $$ = append($$, $3) - } - -index_column: - sql_id length_opt - { - $$ = &IndexColumn{Column: $1, Length: $2} - } - -table_option_list: - { - $$ = "" - } -| table_option - { - $$ = " " + string($1) - } -| table_option_list ',' table_option - { - $$ = string($1) + ", " + string($3) - } - -// rather than explicitly parsing the various keywords for table options, -// just accept any number of keywords, IDs, strings, numbers, and '=' -table_option: - table_opt_value - { - $$ = $1 - } -| table_option table_opt_value - { - $$ = $1 + " " + $2 - } -| table_option '=' table_opt_value - { - $$ = $1 + "=" + $3 - } - -table_opt_value: - reserved_sql_id - { - $$ = $1.String() - } -| STRING - { - $$ = "'" + string($1) + "'" - } -| INTEGRAL - { - $$ = string($1) - } - -alter_statement: - ALTER ignore_opt TABLE table_name non_add_drop_or_rename_operation force_eof - { - $$ = &DDL{Action: AlterStr, Table: $4, NewName: $4} - } -| ALTER ignore_opt TABLE table_name ADD alter_object_type force_eof - { - $$ = &DDL{Action: AlterStr, Table: $4, NewName: $4} - } -| ALTER ignore_opt TABLE table_name DROP alter_object_type force_eof - { - $$ = &DDL{Action: AlterStr, Table: $4, NewName: $4} - } -| ALTER ignore_opt TABLE table_name ADD VINDEX sql_id '(' column_list ')' vindex_type_opt vindex_params_opt - { - $$ = &DDL{ - Action: AddColVindexStr, - Table: $4, - VindexSpec: &VindexSpec{ - Name: $7, - Type: $11, - Params: $12, - }, - VindexCols: $9, - } - } -| ALTER ignore_opt TABLE table_name DROP VINDEX sql_id - { - $$ = &DDL{ - Action: DropColVindexStr, - Table: $4, - VindexSpec: &VindexSpec{ - Name: $7, - }, - } - } -| ALTER ignore_opt TABLE table_name RENAME to_opt table_name - { - // Change this to a rename statement - $$ = &DDL{Action: RenameStr, Table: $4, NewName: $7} - } -| ALTER ignore_opt TABLE table_name RENAME index_opt force_eof - { - // Rename an index can just be an alter - $$ = &DDL{Action: AlterStr, Table: $4, NewName: $4} - } -| ALTER VIEW table_name ddl_force_eof - { - $$ = &DDL{Action: AlterStr, Table: $3.ToViewName(), NewName: $3.ToViewName()} - } -| ALTER ignore_opt TABLE table_name partition_operation - { - $$ = &DDL{Action: AlterStr, Table: $4, PartitionSpec: $5} - } - -alter_object_type: - COLUMN -| CONSTRAINT -| FOREIGN -| FULLTEXT -| ID -| INDEX -| KEY -| PRIMARY -| SPATIAL -| PARTITION -| UNIQUE - -partition_operation: - REORGANIZE PARTITION sql_id INTO openb partition_definitions closeb - { - $$ = &PartitionSpec{Action: ReorganizeStr, Name: $3, Definitions: $6} - } - -partition_definitions: - partition_definition - { - $$ = []*PartitionDefinition{$1} - } -| partition_definitions ',' partition_definition - { - $$ = append($1, $3) - } - -partition_definition: - PARTITION sql_id VALUES LESS THAN openb value_expression closeb - { - $$ = &PartitionDefinition{Name: $2, Limit: $7} - } -| PARTITION sql_id VALUES LESS THAN openb MAXVALUE closeb - { - $$ = &PartitionDefinition{Name: $2, Maxvalue: true} - } - -rename_statement: - RENAME TABLE table_name TO table_name - { - $$ = &DDL{Action: RenameStr, Table: $3, NewName: $5} - } - -drop_statement: - DROP TABLE exists_opt table_name - { - var exists bool - if $3 != 0 { - exists = true - } - $$ = &DDL{Action: DropStr, Table: $4, IfExists: exists} - } -| DROP INDEX ID ON table_name ddl_force_eof - { - // Change this to an alter statement - $$ = &DDL{Action: AlterStr, Table: $5, NewName: $5} - } -| DROP VIEW exists_opt table_name ddl_force_eof - { - var exists bool - if $3 != 0 { - exists = true - } - $$ = &DDL{Action: DropStr, Table: $4.ToViewName(), IfExists: exists} - } -| DROP DATABASE exists_opt ID - { - $$ = &DBDDL{Action: DropStr, DBName: string($4)} - } -| DROP SCHEMA exists_opt ID - { - $$ = &DBDDL{Action: DropStr, DBName: string($4)} - } - -truncate_statement: - TRUNCATE TABLE table_name - { - $$ = &DDL{Action: TruncateStr, Table: $3} - } -| TRUNCATE table_name - { - $$ = &DDL{Action: TruncateStr, Table: $2} - } -analyze_statement: - ANALYZE TABLE table_name - { - $$ = &DDL{Action: AlterStr, Table: $3, NewName: $3} - } - -show_statement: - SHOW BINARY ID ddl_force_eof /* SHOW BINARY LOGS */ - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CHARACTER SET ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CREATE DATABASE ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -/* Rule to handle SHOW CREATE EVENT, SHOW CREATE FUNCTION, etc. */ -| SHOW CREATE ID ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CREATE PROCEDURE ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CREATE TABLE ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CREATE TRIGGER ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW CREATE VIEW ddl_force_eof - { - $$ = &Show{Type: string($2) + " " + string($3)} - } -| SHOW DATABASES ddl_force_eof - { - $$ = &Show{Type: string($2)} - } -| SHOW INDEX ddl_force_eof - { - $$ = &Show{Type: string($2)} - } -| SHOW KEYS ddl_force_eof - { - $$ = &Show{Type: string($2)} - } -| SHOW PROCEDURE ddl_force_eof - { - $$ = &Show{Type: string($2)} - } -| SHOW show_session_or_global STATUS ddl_force_eof - { - $$ = &Show{Scope: $2, Type: string($3)} - } -| SHOW TABLE ddl_force_eof - { - $$ = &Show{Type: string($2)} - } -| SHOW extended_opt full_opt tables_or_processlist from_database_opt like_or_where_opt - { - // this is ugly, but I couldn't find a better way for now - if $4 == "processlist" { - $$ = &Show{Type: $4} - } else { - showTablesOpt := &ShowTablesOpt{Extended: $2, Full:$3, DbName:$5, Filter:$6} - $$ = &Show{Type: $4, ShowTablesOpt: showTablesOpt} - } - } -| SHOW show_session_or_global VARIABLES ddl_force_eof - { - $$ = &Show{Scope: $2, Type: string($3)} - } -| SHOW VINDEXES - { - $$ = &Show{Type: string($2)} - } -| SHOW VINDEXES ON table_name - { - $$ = &Show{Type: string($2), OnTable: $4} - } -| SHOW VITESS_KEYSPACES - { - $$ = &Show{Type: string($2)} - } -| SHOW VITESS_SHARDS - { - $$ = &Show{Type: string($2)} - } -| SHOW VITESS_TABLETS - { - $$ = &Show{Type: string($2)} - } -| SHOW VSCHEMA_TABLES - { - $$ = &Show{Type: string($2)} - } -/* - * Catch-all for show statements without vitess keywords: - * - * SHOW BINARY LOGS - * SHOW INVALID - */ -| SHOW ID ddl_force_eof - { - $$ = &Show{Type: string($2)} - } - -tables_or_processlist: - TABLES - { - $$ = string($1) - } -| PROCESSLIST - { - $$ = string($1) - } - -extended_opt: - /* empty */ - { - $$ = "" - } -| EXTENDED - { - $$ = "extended " - } - -full_opt: - /* empty */ - { - $$ = "" - } -| FULL - { - $$ = "full " - } - -from_database_opt: - /* empty */ - { - $$ = "" - } -| FROM table_id - { - $$ = $2.v - } -| IN table_id - { - $$ = $2.v - } - -like_or_where_opt: - /* empty */ - { - $$ = nil - } -| LIKE STRING - { - $$ = &ShowFilter{Like:string($2)} - } -| WHERE expression - { - $$ = &ShowFilter{Filter:$2} - } - -show_session_or_global: - /* empty */ - { - $$ = "" - } -| SESSION - { - $$ = SessionStr - } -| GLOBAL - { - $$ = GlobalStr - } - -use_statement: - USE table_id - { - $$ = &Use{DBName: $2} - } -| USE - { - $$ = &Use{DBName:TableIdent{v:""}} - } - -begin_statement: - BEGIN - { - $$ = &Begin{} - } -| START TRANSACTION - { - $$ = &Begin{} - } - -commit_statement: - COMMIT - { - $$ = &Commit{} - } - -rollback_statement: - ROLLBACK - { - $$ = &Rollback{} - } - -other_statement: - DESC force_eof - { - $$ = &OtherRead{} - } -| DESCRIBE force_eof - { - $$ = &OtherRead{} - } -| EXPLAIN force_eof - { - $$ = &OtherRead{} - } -| REPAIR force_eof - { - $$ = &OtherAdmin{} - } -| OPTIMIZE force_eof - { - $$ = &OtherAdmin{} - } - -comment_opt: - { - setAllowComments(yylex, true) - } - comment_list - { - $$ = $2 - setAllowComments(yylex, false) - } - -comment_list: - { - $$ = nil - } -| comment_list COMMENT - { - $$ = append($1, $2) - } - -union_op: - UNION - { - $$ = UnionStr - } -| UNION ALL - { - $$ = UnionAllStr - } -| UNION DISTINCT - { - $$ = UnionDistinctStr - } - -cache_opt: -{ - $$ = "" -} -| SQL_NO_CACHE -{ - $$ = SQLNoCacheStr -} -| SQL_CACHE -{ - $$ = SQLCacheStr -} - -distinct_opt: - { - $$ = "" - } -| DISTINCT - { - $$ = DistinctStr - } - -straight_join_opt: - { - $$ = "" - } -| STRAIGHT_JOIN - { - $$ = StraightJoinHint - } - -select_expression_list_opt: - { - $$ = nil - } -| select_expression_list - { - $$ = $1 - } - -select_expression_list: - select_expression - { - $$ = SelectExprs{$1} - } -| select_expression_list ',' select_expression - { - $$ = append($$, $3) - } - -select_expression: - '*' - { - $$ = &StarExpr{} - } -| expression as_ci_opt - { - $$ = &AliasedExpr{Expr: $1, As: $2} - } -| table_id '.' '*' - { - $$ = &StarExpr{TableName: TableName{Name: $1}} - } -| table_id '.' reserved_table_id '.' '*' - { - $$ = &StarExpr{TableName: TableName{Qualifier: $1, Name: $3}} - } - -as_ci_opt: - { - $$ = ColIdent{} - } -| col_alias - { - $$ = $1 - } -| AS col_alias - { - $$ = $2 - } - -col_alias: - sql_id -| STRING - { - $$ = NewColIdent(string($1)) - } - -from_opt: - { - $$ = TableExprs{&AliasedTableExpr{Expr:TableName{Name: NewTableIdent("dual")}}} - } -| FROM table_references - { - $$ = $2 - } - -table_references: - table_reference - { - $$ = TableExprs{$1} - } -| table_references ',' table_reference - { - $$ = append($$, $3) - } - -table_reference: - table_factor -| join_table - -table_factor: - aliased_table_name - { - $$ = $1 - } -| subquery as_opt table_id - { - $$ = &AliasedTableExpr{Expr:$1, As: $3} - } -| openb table_references closeb - { - $$ = &ParenTableExpr{Exprs: $2} - } - -aliased_table_name: -table_name as_opt_id index_hint_list - { - $$ = &AliasedTableExpr{Expr:$1, As: $2, Hints: $3} - } -| table_name PARTITION openb partition_list closeb as_opt_id index_hint_list - { - $$ = &AliasedTableExpr{Expr:$1, Partitions: $4, As: $6, Hints: $7} - } - -column_list: - sql_id - { - $$ = Columns{$1} - } -| column_list ',' sql_id - { - $$ = append($$, $3) - } - -partition_list: - sql_id - { - $$ = Partitions{$1} - } -| partition_list ',' sql_id - { - $$ = append($$, $3) - } - -// There is a grammar conflict here: -// 1: INSERT INTO a SELECT * FROM b JOIN c ON b.i = c.i -// 2: INSERT INTO a SELECT * FROM b JOIN c ON DUPLICATE KEY UPDATE a.i = 1 -// When yacc encounters the ON clause, it cannot determine which way to -// resolve. The %prec override below makes the parser choose the -// first construct, which automatically makes the second construct a -// syntax error. This is the same behavior as MySQL. -join_table: - table_reference inner_join table_factor join_condition_opt - { - $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4} - } -| table_reference straight_join table_factor on_expression_opt - { - $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4} - } -| table_reference outer_join table_reference join_condition - { - $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4} - } -| table_reference natural_join table_factor - { - $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3} - } - -join_condition: - ON expression - { $$ = JoinCondition{On: $2} } -| USING '(' column_list ')' - { $$ = JoinCondition{Using: $3} } - -join_condition_opt: -%prec JOIN - { $$ = JoinCondition{} } -| join_condition - { $$ = $1 } - -on_expression_opt: -%prec JOIN - { $$ = JoinCondition{} } -| ON expression - { $$ = JoinCondition{On: $2} } - -as_opt: - { $$ = struct{}{} } -| AS - { $$ = struct{}{} } - -as_opt_id: - { - $$ = NewTableIdent("") - } -| table_alias - { - $$ = $1 - } -| AS table_alias - { - $$ = $2 - } - -table_alias: - table_id -| STRING - { - $$ = NewTableIdent(string($1)) - } - -inner_join: - JOIN - { - $$ = JoinStr - } -| INNER JOIN - { - $$ = JoinStr - } -| CROSS JOIN - { - $$ = JoinStr - } - -straight_join: - STRAIGHT_JOIN - { - $$ = StraightJoinStr - } - -outer_join: - LEFT JOIN - { - $$ = LeftJoinStr - } -| LEFT OUTER JOIN - { - $$ = LeftJoinStr - } -| RIGHT JOIN - { - $$ = RightJoinStr - } -| RIGHT OUTER JOIN - { - $$ = RightJoinStr - } - -natural_join: - NATURAL JOIN - { - $$ = NaturalJoinStr - } -| NATURAL outer_join - { - if $2 == LeftJoinStr { - $$ = NaturalLeftJoinStr - } else { - $$ = NaturalRightJoinStr - } - } - -into_table_name: - INTO table_name - { - $$ = $2 - } -| table_name - { - $$ = $1 - } - -table_name: - table_id - { - $$ = TableName{Name: $1} - } -| table_id '.' reserved_table_id - { - $$ = TableName{Qualifier: $1, Name: $3} - } - -index_hint_list: - { - $$ = nil - } -| USE INDEX openb column_list closeb - { - $$ = &IndexHints{Type: UseStr, Indexes: $4} - } -| IGNORE INDEX openb column_list closeb - { - $$ = &IndexHints{Type: IgnoreStr, Indexes: $4} - } -| FORCE INDEX openb column_list closeb - { - $$ = &IndexHints{Type: ForceStr, Indexes: $4} - } - -where_expression_opt: - { - $$ = nil - } -| WHERE expression - { - $$ = $2 - } - -expression: - condition - { - $$ = $1 - } -| expression AND expression - { - $$ = &AndExpr{Left: $1, Right: $3} - } -| expression OR expression - { - $$ = &OrExpr{Left: $1, Right: $3} - } -| NOT expression - { - $$ = &NotExpr{Expr: $2} - } -| expression IS is_suffix - { - $$ = &IsExpr{Operator: $3, Expr: $1} - } -| value_expression - { - $$ = $1 - } -| DEFAULT default_opt - { - $$ = &Default{ColName: $2} - } - -default_opt: - /* empty */ - { - $$ = "" - } -| openb ID closeb - { - $$ = string($2) - } - -boolean_value: - TRUE - { - $$ = BoolVal(true) - } -| FALSE - { - $$ = BoolVal(false) - } - -condition: - value_expression compare value_expression - { - $$ = &ComparisonExpr{Left: $1, Operator: $2, Right: $3} - } -| value_expression IN col_tuple - { - $$ = &ComparisonExpr{Left: $1, Operator: InStr, Right: $3} - } -| value_expression NOT IN col_tuple - { - $$ = &ComparisonExpr{Left: $1, Operator: NotInStr, Right: $4} - } -| value_expression LIKE value_expression like_escape_opt - { - $$ = &ComparisonExpr{Left: $1, Operator: LikeStr, Right: $3, Escape: $4} - } -| value_expression NOT LIKE value_expression like_escape_opt - { - $$ = &ComparisonExpr{Left: $1, Operator: NotLikeStr, Right: $4, Escape: $5} - } -| value_expression REGEXP value_expression - { - $$ = &ComparisonExpr{Left: $1, Operator: RegexpStr, Right: $3} - } -| value_expression NOT REGEXP value_expression - { - $$ = &ComparisonExpr{Left: $1, Operator: NotRegexpStr, Right: $4} - } -| value_expression BETWEEN value_expression AND value_expression - { - $$ = &RangeCond{Left: $1, Operator: BetweenStr, From: $3, To: $5} - } -| value_expression NOT BETWEEN value_expression AND value_expression - { - $$ = &RangeCond{Left: $1, Operator: NotBetweenStr, From: $4, To: $6} - } -| EXISTS subquery - { - $$ = &ExistsExpr{Subquery: $2} - } - -is_suffix: - NULL - { - $$ = IsNullStr - } -| NOT NULL - { - $$ = IsNotNullStr - } -| TRUE - { - $$ = IsTrueStr - } -| NOT TRUE - { - $$ = IsNotTrueStr - } -| FALSE - { - $$ = IsFalseStr - } -| NOT FALSE - { - $$ = IsNotFalseStr - } - -compare: - '=' - { - $$ = EqualStr - } -| '<' - { - $$ = LessThanStr - } -| '>' - { - $$ = GreaterThanStr - } -| LE - { - $$ = LessEqualStr - } -| GE - { - $$ = GreaterEqualStr - } -| NE - { - $$ = NotEqualStr - } -| NULL_SAFE_EQUAL - { - $$ = NullSafeEqualStr - } - -like_escape_opt: - { - $$ = nil - } -| ESCAPE value_expression - { - $$ = $2 - } - -col_tuple: - row_tuple - { - $$ = $1 - } -| subquery - { - $$ = $1 - } -| LIST_ARG - { - $$ = ListArg($1) - } - -subquery: - openb select_statement closeb - { - $$ = &Subquery{$2} - } - -expression_list: - expression - { - $$ = Exprs{$1} - } -| expression_list ',' expression - { - $$ = append($1, $3) - } - -value_expression: - value - { - $$ = $1 - } -| boolean_value - { - $$ = $1 - } -| column_name - { - $$ = $1 - } -| tuple_expression - { - $$ = $1 - } -| subquery - { - $$ = $1 - } -| value_expression '&' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: BitAndStr, Right: $3} - } -| value_expression '|' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: BitOrStr, Right: $3} - } -| value_expression '^' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: BitXorStr, Right: $3} - } -| value_expression '+' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: PlusStr, Right: $3} - } -| value_expression '-' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: MinusStr, Right: $3} - } -| value_expression '*' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: MultStr, Right: $3} - } -| value_expression '/' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: DivStr, Right: $3} - } -| value_expression DIV value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: IntDivStr, Right: $3} - } -| value_expression '%' value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: ModStr, Right: $3} - } -| value_expression MOD value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: ModStr, Right: $3} - } -| value_expression SHIFT_LEFT value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: ShiftLeftStr, Right: $3} - } -| value_expression SHIFT_RIGHT value_expression - { - $$ = &BinaryExpr{Left: $1, Operator: ShiftRightStr, Right: $3} - } -| column_name JSON_EXTRACT_OP value - { - $$ = &BinaryExpr{Left: $1, Operator: JSONExtractOp, Right: $3} - } -| column_name JSON_UNQUOTE_EXTRACT_OP value - { - $$ = &BinaryExpr{Left: $1, Operator: JSONUnquoteExtractOp, Right: $3} - } -| value_expression COLLATE charset - { - $$ = &CollateExpr{Expr: $1, Charset: $3} - } -| BINARY value_expression %prec UNARY - { - $$ = &UnaryExpr{Operator: BinaryStr, Expr: $2} - } -| UNDERSCORE_BINARY value_expression %prec UNARY - { - $$ = &UnaryExpr{Operator: UBinaryStr, Expr: $2} - } -| '+' value_expression %prec UNARY - { - if num, ok := $2.(*SQLVal); ok && num.Type == IntVal { - $$ = num - } else { - $$ = &UnaryExpr{Operator: UPlusStr, Expr: $2} - } - } -| '-' value_expression %prec UNARY - { - if num, ok := $2.(*SQLVal); ok && num.Type == IntVal { - // Handle double negative - if num.Val[0] == '-' { - num.Val = num.Val[1:] - $$ = num - } else { - $$ = NewIntVal(append([]byte("-"), num.Val...)) - } - } else { - $$ = &UnaryExpr{Operator: UMinusStr, Expr: $2} - } - } -| '~' value_expression - { - $$ = &UnaryExpr{Operator: TildaStr, Expr: $2} - } -| '!' value_expression %prec UNARY - { - $$ = &UnaryExpr{Operator: BangStr, Expr: $2} - } -| INTERVAL value_expression sql_id - { - // This rule prevents the usage of INTERVAL - // as a function. If support is needed for that, - // we'll need to revisit this. The solution - // will be non-trivial because of grammar conflicts. - $$ = &IntervalExpr{Expr: $2, Unit: $3.String()} - } -| function_call_generic -| function_call_keyword -| function_call_nonkeyword -| function_call_conflict - -/* - Regular function calls without special token or syntax, guaranteed to not - introduce side effects due to being a simple identifier -*/ -function_call_generic: - sql_id openb select_expression_list_opt closeb - { - $$ = &FuncExpr{Name: $1, Exprs: $3} - } -| sql_id openb DISTINCT select_expression_list closeb - { - $$ = &FuncExpr{Name: $1, Distinct: true, Exprs: $4} - } -| table_id '.' reserved_sql_id openb select_expression_list_opt closeb - { - $$ = &FuncExpr{Qualifier: $1, Name: $3, Exprs: $5} - } - -/* - Function calls using reserved keywords, with dedicated grammar rules - as a result -*/ -function_call_keyword: - LEFT openb select_expression_list closeb - { - $$ = &FuncExpr{Name: NewColIdent("left"), Exprs: $3} - } -| RIGHT openb select_expression_list closeb - { - $$ = &FuncExpr{Name: NewColIdent("right"), Exprs: $3} - } -| CONVERT openb expression ',' convert_type closeb - { - $$ = &ConvertExpr{Expr: $3, Type: $5} - } -| CAST openb expression AS convert_type closeb - { - $$ = &ConvertExpr{Expr: $3, Type: $5} - } -| CONVERT openb expression USING charset closeb - { - $$ = &ConvertUsingExpr{Expr: $3, Type: $5} - } -| SUBSTR openb column_name ',' value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: nil} - } -| SUBSTR openb column_name ',' value_expression ',' value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: $7} - } -| SUBSTR openb column_name FROM value_expression FOR value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: $7} - } -| SUBSTRING openb column_name ',' value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: nil} - } -| SUBSTRING openb column_name ',' value_expression ',' value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: $7} - } -| SUBSTRING openb column_name FROM value_expression FOR value_expression closeb - { - $$ = &SubstrExpr{Name: $3, From: $5, To: $7} - } -| MATCH openb select_expression_list closeb AGAINST openb value_expression match_option closeb - { - $$ = &MatchExpr{Columns: $3, Expr: $7, Option: $8} - } -| GROUP_CONCAT openb distinct_opt select_expression_list order_by_opt separator_opt closeb - { - $$ = &GroupConcatExpr{Distinct: $3, Exprs: $4, OrderBy: $5, Separator: $6} - } -| CASE expression_opt when_expression_list else_expression_opt END - { - $$ = &CaseExpr{Expr: $2, Whens: $3, Else: $4} - } -| VALUES openb column_name closeb - { - $$ = &ValuesFuncExpr{Name: $3} - } - -/* - Function calls using non reserved keywords but with special syntax forms. - Dedicated grammar rules are needed because of the special syntax -*/ -function_call_nonkeyword: - CURRENT_TIMESTAMP func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("current_timestamp")} - } -| UTC_TIMESTAMP func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("utc_timestamp")} - } -| UTC_TIME func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("utc_time")} - } -| UTC_DATE func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("utc_date")} - } - // now -| LOCALTIME func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("localtime")} - } - // now -| LOCALTIMESTAMP func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("localtimestamp")} - } - // curdate -| CURRENT_DATE func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("current_date")} - } - // curtime -| CURRENT_TIME func_datetime_precision_opt - { - $$ = &FuncExpr{Name:NewColIdent("current_time")} - } - -func_datetime_precision_opt: - /* empty */ -| openb closeb - -/* - Function calls using non reserved keywords with *normal* syntax forms. Because - the names are non-reserved, they need a dedicated rule so as not to conflict -*/ -function_call_conflict: - IF openb select_expression_list closeb - { - $$ = &FuncExpr{Name: NewColIdent("if"), Exprs: $3} - } -| DATABASE openb select_expression_list_opt closeb - { - $$ = &FuncExpr{Name: NewColIdent("database"), Exprs: $3} - } -| MOD openb select_expression_list closeb - { - $$ = &FuncExpr{Name: NewColIdent("mod"), Exprs: $3} - } -| REPLACE openb select_expression_list closeb - { - $$ = &FuncExpr{Name: NewColIdent("replace"), Exprs: $3} - } - -match_option: -/*empty*/ - { - $$ = "" - } -| IN BOOLEAN MODE - { - $$ = BooleanModeStr - } -| IN NATURAL LANGUAGE MODE - { - $$ = NaturalLanguageModeStr - } -| IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION - { - $$ = NaturalLanguageModeWithQueryExpansionStr - } -| WITH QUERY EXPANSION - { - $$ = QueryExpansionStr - } - -charset: - ID -{ - $$ = string($1) -} -| STRING -{ - $$ = string($1) -} - -convert_type: - BINARY length_opt - { - $$ = &ConvertType{Type: string($1), Length: $2} - } -| CHAR length_opt charset_opt - { - $$ = &ConvertType{Type: string($1), Length: $2, Charset: $3, Operator: CharacterSetStr} - } -| CHAR length_opt ID - { - $$ = &ConvertType{Type: string($1), Length: $2, Charset: string($3)} - } -| DATE - { - $$ = &ConvertType{Type: string($1)} - } -| DATETIME length_opt - { - $$ = &ConvertType{Type: string($1), Length: $2} - } -| DECIMAL decimal_length_opt - { - $$ = &ConvertType{Type: string($1)} - $$.Length = $2.Length - $$.Scale = $2.Scale - } -| JSON - { - $$ = &ConvertType{Type: string($1)} - } -| NCHAR length_opt - { - $$ = &ConvertType{Type: string($1), Length: $2} - } -| SIGNED - { - $$ = &ConvertType{Type: string($1)} - } -| SIGNED INTEGER - { - $$ = &ConvertType{Type: string($1)} - } -| TIME length_opt - { - $$ = &ConvertType{Type: string($1), Length: $2} - } -| UNSIGNED - { - $$ = &ConvertType{Type: string($1)} - } -| UNSIGNED INTEGER - { - $$ = &ConvertType{Type: string($1)} - } - -expression_opt: - { - $$ = nil - } -| expression - { - $$ = $1 - } - -separator_opt: - { - $$ = string("") - } -| SEPARATOR STRING - { - $$ = " separator '"+string($2)+"'" - } - -when_expression_list: - when_expression - { - $$ = []*When{$1} - } -| when_expression_list when_expression - { - $$ = append($1, $2) - } - -when_expression: - WHEN expression THEN expression - { - $$ = &When{Cond: $2, Val: $4} - } - -else_expression_opt: - { - $$ = nil - } -| ELSE expression - { - $$ = $2 - } - -column_name: - sql_id - { - $$ = &ColName{Name: $1} - } -| table_id '.' reserved_sql_id - { - $$ = &ColName{Qualifier: TableName{Name: $1}, Name: $3} - } -| table_id '.' reserved_table_id '.' reserved_sql_id - { - $$ = &ColName{Qualifier: TableName{Qualifier: $1, Name: $3}, Name: $5} - } - -value: - STRING - { - $$ = NewStrVal($1) - } -| HEX - { - $$ = NewHexVal($1) - } -| BIT_LITERAL - { - $$ = NewBitVal($1) - } -| INTEGRAL - { - $$ = NewIntVal($1) - } -| FLOAT - { - $$ = NewFloatVal($1) - } -| HEXNUM - { - $$ = NewHexNum($1) - } -| VALUE_ARG - { - $$ = NewValArg($1) - } -| NULL - { - $$ = &NullVal{} - } - -num_val: - sql_id - { - // TODO(sougou): Deprecate this construct. - if $1.Lowered() != "value" { - yylex.Error("expecting value after next") - return 1 - } - $$ = NewIntVal([]byte("1")) - } -| INTEGRAL VALUES - { - $$ = NewIntVal($1) - } -| VALUE_ARG VALUES - { - $$ = NewValArg($1) - } - -group_by_opt: - { - $$ = nil - } -| GROUP BY expression_list - { - $$ = $3 - } - -having_opt: - { - $$ = nil - } -| HAVING expression - { - $$ = $2 - } - -order_by_opt: - { - $$ = nil - } -| ORDER BY order_list - { - $$ = $3 - } - -order_list: - order - { - $$ = OrderBy{$1} - } -| order_list ',' order - { - $$ = append($1, $3) - } - -order: - expression asc_desc_opt - { - $$ = &Order{Expr: $1, Direction: $2} - } - -asc_desc_opt: - { - $$ = AscScr - } -| ASC - { - $$ = AscScr - } -| DESC - { - $$ = DescScr - } - -limit_opt: - { - $$ = nil - } -| LIMIT expression - { - $$ = &Limit{Rowcount: $2} - } -| LIMIT expression ',' expression - { - $$ = &Limit{Offset: $2, Rowcount: $4} - } -| LIMIT expression OFFSET expression - { - $$ = &Limit{Offset: $4, Rowcount: $2} - } - -lock_opt: - { - $$ = "" - } -| FOR UPDATE - { - $$ = ForUpdateStr - } -| LOCK IN SHARE MODE - { - $$ = ShareModeStr - } - -// insert_data expands all combinations into a single rule. -// This avoids a shift/reduce conflict while encountering the -// following two possible constructs: -// insert into t1(a, b) (select * from t2) -// insert into t1(select * from t2) -// Because the rules are together, the parser can keep shifting -// the tokens until it disambiguates a as sql_id and select as keyword. -insert_data: - VALUES tuple_list - { - $$ = &Insert{Rows: $2} - } -| select_statement - { - $$ = &Insert{Rows: $1} - } -| openb select_statement closeb - { - // Drop the redundant parenthesis. - $$ = &Insert{Rows: $2} - } -| openb ins_column_list closeb VALUES tuple_list - { - $$ = &Insert{Columns: $2, Rows: $5} - } -| openb ins_column_list closeb select_statement - { - $$ = &Insert{Columns: $2, Rows: $4} - } -| openb ins_column_list closeb openb select_statement closeb - { - // Drop the redundant parenthesis. - $$ = &Insert{Columns: $2, Rows: $5} - } - -ins_column_list: - sql_id - { - $$ = Columns{$1} - } -| sql_id '.' sql_id - { - $$ = Columns{$3} - } -| ins_column_list ',' sql_id - { - $$ = append($$, $3) - } -| ins_column_list ',' sql_id '.' sql_id - { - $$ = append($$, $5) - } - -on_dup_opt: - { - $$ = nil - } -| ON DUPLICATE KEY UPDATE update_list - { - $$ = $5 - } - -tuple_list: - tuple_or_empty - { - $$ = Values{$1} - } -| tuple_list ',' tuple_or_empty - { - $$ = append($1, $3) - } - -tuple_or_empty: - row_tuple - { - $$ = $1 - } -| openb closeb - { - $$ = ValTuple{} - } - -row_tuple: - openb expression_list closeb - { - $$ = ValTuple($2) - } - -tuple_expression: - row_tuple - { - if len($1) == 1 { - $$ = &ParenExpr{$1[0]} - } else { - $$ = $1 - } - } - -update_list: - update_expression - { - $$ = UpdateExprs{$1} - } -| update_list ',' update_expression - { - $$ = append($1, $3) - } - -update_expression: - column_name '=' expression - { - $$ = &UpdateExpr{Name: $1, Expr: $3} - } - -set_list: - set_expression - { - $$ = SetExprs{$1} - } -| set_list ',' set_expression - { - $$ = append($1, $3) - } - -set_expression: - reserved_sql_id '=' ON - { - $$ = &SetExpr{Name: $1, Expr: NewStrVal([]byte("on"))} - } -| reserved_sql_id '=' expression - { - $$ = &SetExpr{Name: $1, Expr: $3} - } -| charset_or_character_set charset_value collate_opt - { - $$ = &SetExpr{Name: NewColIdent(string($1)), Expr: $2} - } - -charset_or_character_set: - CHARSET -| CHARACTER SET - { - $$ = []byte("charset") - } -| NAMES - -charset_value: - sql_id - { - $$ = NewStrVal([]byte($1.String())) - } -| STRING - { - $$ = NewStrVal($1) - } -| DEFAULT - { - $$ = &Default{} - } - -for_from: - FOR -| FROM - -exists_opt: - { $$ = 0 } -| IF EXISTS - { $$ = 1 } - -not_exists_opt: - { $$ = struct{}{} } -| IF NOT EXISTS - { $$ = struct{}{} } - -ignore_opt: - { $$ = "" } -| IGNORE - { $$ = IgnoreStr } - -non_add_drop_or_rename_operation: - ALTER - { $$ = struct{}{} } -| AUTO_INCREMENT - { $$ = struct{}{} } -| CHARACTER - { $$ = struct{}{} } -| COMMENT_KEYWORD - { $$ = struct{}{} } -| DEFAULT - { $$ = struct{}{} } -| ORDER - { $$ = struct{}{} } -| CONVERT - { $$ = struct{}{} } -| PARTITION - { $$ = struct{}{} } -| UNUSED - { $$ = struct{}{} } -| ID - { $$ = struct{}{} } - -to_opt: - { $$ = struct{}{} } -| TO - { $$ = struct{}{} } -| AS - { $$ = struct{}{} } - -index_opt: - INDEX - { $$ = struct{}{} } -| KEY - { $$ = struct{}{} } - -constraint_opt: - { $$ = struct{}{} } -| UNIQUE - { $$ = struct{}{} } -| sql_id - { $$ = struct{}{} } - -using_opt: - { $$ = ColIdent{} } -| USING sql_id - { $$ = $2 } - -sql_id: - ID - { - $$ = NewColIdent(string($1)) - } -| non_reserved_keyword - { - $$ = NewColIdent(string($1)) - } - -reserved_sql_id: - sql_id -| reserved_keyword - { - $$ = NewColIdent(string($1)) - } - -table_id: - ID - { - $$ = NewTableIdent(string($1)) - } -| non_reserved_keyword - { - $$ = NewTableIdent(string($1)) - } - -reserved_table_id: - table_id -| reserved_keyword - { - $$ = NewTableIdent(string($1)) - } - -/* - These are not all necessarily reserved in MySQL, but some are. - - These are more importantly reserved because they may conflict with our grammar. - If you want to move one that is not reserved in MySQL (i.e. ESCAPE) to the - non_reserved_keywords, you'll need to deal with any conflicts. - - Sorted alphabetically -*/ -reserved_keyword: - ADD -| AND -| AS -| ASC -| AUTO_INCREMENT -| BETWEEN -| BINARY -| BY -| CASE -| COLLATE -| CONVERT -| CREATE -| CROSS -| CURRENT_DATE -| CURRENT_TIME -| CURRENT_TIMESTAMP -| SUBSTR -| SUBSTRING -| DATABASE -| DATABASES -| DEFAULT -| DELETE -| DESC -| DESCRIBE -| DISTINCT -| DIV -| DROP -| ELSE -| END -| ESCAPE -| EXISTS -| EXPLAIN -| FALSE -| FOR -| FORCE -| FROM -| GROUP -| HAVING -| IF -| IGNORE -| IN -| INDEX -| INNER -| INSERT -| INTERVAL -| INTO -| IS -| JOIN -| KEY -| LEFT -| LIKE -| LIMIT -| LOCALTIME -| LOCALTIMESTAMP -| LOCK -| MATCH -| MAXVALUE -| MOD -| NATURAL -| NEXT // next should be doable as non-reserved, but is not due to the special `select next num_val` query that vitess supports -| NOT -| NULL -| ON -| OR -| ORDER -| OUTER -| REGEXP -| RENAME -| REPLACE -| RIGHT -| SCHEMA -| SELECT -| SEPARATOR -| SET -| SHOW -| STRAIGHT_JOIN -| TABLE -| TABLES -| THEN -| TO -| TRUE -| UNION -| UNIQUE -| UPDATE -| USE -| USING -| UTC_DATE -| UTC_TIME -| UTC_TIMESTAMP -| VALUES -| WHEN -| WHERE - -/* - These are non-reserved Vitess, because they don't cause conflicts in the grammar. - Some of them may be reserved in MySQL. The good news is we backtick quote them - when we rewrite the query, so no issue should arise. - - Sorted alphabetically -*/ -non_reserved_keyword: - AGAINST -| BEGIN -| BIGINT -| BIT -| BLOB -| BOOL -| CHAR -| CHARACTER -| CHARSET -| COMMENT_KEYWORD -| COMMIT -| COMMITTED -| DATE -| DATETIME -| DECIMAL -| DOUBLE -| DUPLICATE -| ENUM -| EXPANSION -| FLOAT_TYPE -| FOREIGN -| FULLTEXT -| GEOMETRY -| GEOMETRYCOLLECTION -| GLOBAL -| INT -| INTEGER -| ISOLATION -| JSON -| KEY_BLOCK_SIZE -| KEYS -| LANGUAGE -| LAST_INSERT_ID -| LESS -| LEVEL -| LINESTRING -| LONGBLOB -| LONGTEXT -| MEDIUMBLOB -| MEDIUMINT -| MEDIUMTEXT -| MODE -| MULTILINESTRING -| MULTIPOINT -| MULTIPOLYGON -| NAMES -| NCHAR -| NUMERIC -| OFFSET -| ONLY -| OPTIMIZE -| PARTITION -| POINT -| POLYGON -| PRIMARY -| PROCEDURE -| QUERY -| READ -| REAL -| REORGANIZE -| REPAIR -| REPEATABLE -| ROLLBACK -| SESSION -| SERIALIZABLE -| SHARE -| SIGNED -| SMALLINT -| SPATIAL -| START -| STATUS -| TEXT -| THAN -| TIME -| TIMESTAMP -| TINYBLOB -| TINYINT -| TINYTEXT -| TRANSACTION -| TRIGGER -| TRUNCATE -| UNCOMMITTED -| UNSIGNED -| UNUSED -| VARBINARY -| VARCHAR -| VARIABLES -| VIEW -| VINDEX -| VINDEXES -| VITESS_KEYSPACES -| VITESS_SHARDS -| VITESS_TABLETS -| VSCHEMA_TABLES -| WITH -| WRITE -| YEAR -| ZEROFILL - -openb: - '(' - { - if incNesting(yylex) { - yylex.Error("max nesting level reached") - return 1 - } - } - -closeb: - ')' - { - decNesting(yylex) - } - -force_eof: -{ - forceEOF(yylex) -} - -ddl_force_eof: - { - forceEOF(yylex) - } -| openb - { - forceEOF(yylex) - } -| reserved_sql_id - { - forceEOF(yylex) - } diff --git a/vendor/github.com/xwb1989/sqlparser/token.go b/vendor/github.com/xwb1989/sqlparser/token.go deleted file mode 100644 index 23efa77cf..000000000 --- a/vendor/github.com/xwb1989/sqlparser/token.go +++ /dev/null @@ -1,950 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "bytes" - "errors" - "fmt" - "io" - - "github.com/xwb1989/sqlparser/dependency/bytes2" - "github.com/xwb1989/sqlparser/dependency/sqltypes" -) - -const ( - defaultBufSize = 4096 - eofChar = 0x100 -) - -// Tokenizer is the struct used to generate SQL -// tokens for the parser. -type Tokenizer struct { - InStream io.Reader - AllowComments bool - ForceEOF bool - lastChar uint16 - Position int - lastToken []byte - LastError error - posVarIndex int - ParseTree Statement - partialDDL *DDL - nesting int - multi bool - specialComment *Tokenizer - - buf []byte - bufPos int - bufSize int -} - -// NewStringTokenizer creates a new Tokenizer for the -// sql string. -func NewStringTokenizer(sql string) *Tokenizer { - buf := []byte(sql) - return &Tokenizer{ - buf: buf, - bufSize: len(buf), - } -} - -// NewTokenizer creates a new Tokenizer reading a sql -// string from the io.Reader. -func NewTokenizer(r io.Reader) *Tokenizer { - return &Tokenizer{ - InStream: r, - buf: make([]byte, defaultBufSize), - } -} - -// keywords is a map of mysql keywords that fall into two categories: -// 1) keywords considered reserved by MySQL -// 2) keywords for us to handle specially in sql.y -// -// Those marked as UNUSED are likely reserved keywords. We add them here so that -// when rewriting queries we can properly backtick quote them so they don't cause issues -// -// NOTE: If you add new keywords, add them also to the reserved_keywords or -// non_reserved_keywords grammar in sql.y -- this will allow the keyword to be used -// in identifiers. See the docs for each grammar to determine which one to put it into. -var keywords = map[string]int{ - "accessible": UNUSED, - "add": ADD, - "against": AGAINST, - "all": ALL, - "alter": ALTER, - "analyze": ANALYZE, - "and": AND, - "as": AS, - "asc": ASC, - "asensitive": UNUSED, - "auto_increment": AUTO_INCREMENT, - "before": UNUSED, - "begin": BEGIN, - "between": BETWEEN, - "bigint": BIGINT, - "binary": BINARY, - "_binary": UNDERSCORE_BINARY, - "bit": BIT, - "blob": BLOB, - "bool": BOOL, - "boolean": BOOLEAN, - "both": UNUSED, - "by": BY, - "call": UNUSED, - "cascade": UNUSED, - "case": CASE, - "cast": CAST, - "change": UNUSED, - "char": CHAR, - "character": CHARACTER, - "charset": CHARSET, - "check": UNUSED, - "collate": COLLATE, - "column": COLUMN, - "comment": COMMENT_KEYWORD, - "committed": COMMITTED, - "commit": COMMIT, - "condition": UNUSED, - "constraint": CONSTRAINT, - "continue": UNUSED, - "convert": CONVERT, - "substr": SUBSTR, - "substring": SUBSTRING, - "create": CREATE, - "cross": CROSS, - "current_date": CURRENT_DATE, - "current_time": CURRENT_TIME, - "current_timestamp": CURRENT_TIMESTAMP, - "current_user": UNUSED, - "cursor": UNUSED, - "database": DATABASE, - "databases": DATABASES, - "day_hour": UNUSED, - "day_microsecond": UNUSED, - "day_minute": UNUSED, - "day_second": UNUSED, - "date": DATE, - "datetime": DATETIME, - "dec": UNUSED, - "decimal": DECIMAL, - "declare": UNUSED, - "default": DEFAULT, - "delayed": UNUSED, - "delete": DELETE, - "desc": DESC, - "describe": DESCRIBE, - "deterministic": UNUSED, - "distinct": DISTINCT, - "distinctrow": UNUSED, - "div": DIV, - "double": DOUBLE, - "drop": DROP, - "duplicate": DUPLICATE, - "each": UNUSED, - "else": ELSE, - "elseif": UNUSED, - "enclosed": UNUSED, - "end": END, - "enum": ENUM, - "escape": ESCAPE, - "escaped": UNUSED, - "exists": EXISTS, - "exit": UNUSED, - "explain": EXPLAIN, - "expansion": EXPANSION, - "extended": EXTENDED, - "false": FALSE, - "fetch": UNUSED, - "float": FLOAT_TYPE, - "float4": UNUSED, - "float8": UNUSED, - "for": FOR, - "force": FORCE, - "foreign": FOREIGN, - "from": FROM, - "full": FULL, - "fulltext": FULLTEXT, - "generated": UNUSED, - "geometry": GEOMETRY, - "geometrycollection": GEOMETRYCOLLECTION, - "get": UNUSED, - "global": GLOBAL, - "grant": UNUSED, - "group": GROUP, - "group_concat": GROUP_CONCAT, - "having": HAVING, - "high_priority": UNUSED, - "hour_microsecond": UNUSED, - "hour_minute": UNUSED, - "hour_second": UNUSED, - "if": IF, - "ignore": IGNORE, - "in": IN, - "index": INDEX, - "infile": UNUSED, - "inout": UNUSED, - "inner": INNER, - "insensitive": UNUSED, - "insert": INSERT, - "int": INT, - "int1": UNUSED, - "int2": UNUSED, - "int3": UNUSED, - "int4": UNUSED, - "int8": UNUSED, - "integer": INTEGER, - "interval": INTERVAL, - "into": INTO, - "io_after_gtids": UNUSED, - "is": IS, - "isolation": ISOLATION, - "iterate": UNUSED, - "join": JOIN, - "json": JSON, - "key": KEY, - "keys": KEYS, - "key_block_size": KEY_BLOCK_SIZE, - "kill": UNUSED, - "language": LANGUAGE, - "last_insert_id": LAST_INSERT_ID, - "leading": UNUSED, - "leave": UNUSED, - "left": LEFT, - "less": LESS, - "level": LEVEL, - "like": LIKE, - "limit": LIMIT, - "linear": UNUSED, - "lines": UNUSED, - "linestring": LINESTRING, - "load": UNUSED, - "localtime": LOCALTIME, - "localtimestamp": LOCALTIMESTAMP, - "lock": LOCK, - "long": UNUSED, - "longblob": LONGBLOB, - "longtext": LONGTEXT, - "loop": UNUSED, - "low_priority": UNUSED, - "master_bind": UNUSED, - "match": MATCH, - "maxvalue": MAXVALUE, - "mediumblob": MEDIUMBLOB, - "mediumint": MEDIUMINT, - "mediumtext": MEDIUMTEXT, - "middleint": UNUSED, - "minute_microsecond": UNUSED, - "minute_second": UNUSED, - "mod": MOD, - "mode": MODE, - "modifies": UNUSED, - "multilinestring": MULTILINESTRING, - "multipoint": MULTIPOINT, - "multipolygon": MULTIPOLYGON, - "names": NAMES, - "natural": NATURAL, - "nchar": NCHAR, - "next": NEXT, - "not": NOT, - "no_write_to_binlog": UNUSED, - "null": NULL, - "numeric": NUMERIC, - "offset": OFFSET, - "on": ON, - "only": ONLY, - "optimize": OPTIMIZE, - "optimizer_costs": UNUSED, - "option": UNUSED, - "optionally": UNUSED, - "or": OR, - "order": ORDER, - "out": UNUSED, - "outer": OUTER, - "outfile": UNUSED, - "partition": PARTITION, - "point": POINT, - "polygon": POLYGON, - "precision": UNUSED, - "primary": PRIMARY, - "processlist": PROCESSLIST, - "procedure": PROCEDURE, - "query": QUERY, - "range": UNUSED, - "read": READ, - "reads": UNUSED, - "read_write": UNUSED, - "real": REAL, - "references": UNUSED, - "regexp": REGEXP, - "release": UNUSED, - "rename": RENAME, - "reorganize": REORGANIZE, - "repair": REPAIR, - "repeat": UNUSED, - "repeatable": REPEATABLE, - "replace": REPLACE, - "require": UNUSED, - "resignal": UNUSED, - "restrict": UNUSED, - "return": UNUSED, - "revoke": UNUSED, - "right": RIGHT, - "rlike": REGEXP, - "rollback": ROLLBACK, - "schema": SCHEMA, - "schemas": UNUSED, - "second_microsecond": UNUSED, - "select": SELECT, - "sensitive": UNUSED, - "separator": SEPARATOR, - "serializable": SERIALIZABLE, - "session": SESSION, - "set": SET, - "share": SHARE, - "show": SHOW, - "signal": UNUSED, - "signed": SIGNED, - "smallint": SMALLINT, - "spatial": SPATIAL, - "specific": UNUSED, - "sql": UNUSED, - "sqlexception": UNUSED, - "sqlstate": UNUSED, - "sqlwarning": UNUSED, - "sql_big_result": UNUSED, - "sql_cache": SQL_CACHE, - "sql_calc_found_rows": UNUSED, - "sql_no_cache": SQL_NO_CACHE, - "sql_small_result": UNUSED, - "ssl": UNUSED, - "start": START, - "starting": UNUSED, - "status": STATUS, - "stored": UNUSED, - "straight_join": STRAIGHT_JOIN, - "stream": STREAM, - "table": TABLE, - "tables": TABLES, - "terminated": UNUSED, - "text": TEXT, - "than": THAN, - "then": THEN, - "time": TIME, - "timestamp": TIMESTAMP, - "tinyblob": TINYBLOB, - "tinyint": TINYINT, - "tinytext": TINYTEXT, - "to": TO, - "trailing": UNUSED, - "transaction": TRANSACTION, - "trigger": TRIGGER, - "true": TRUE, - "truncate": TRUNCATE, - "uncommitted": UNCOMMITTED, - "undo": UNUSED, - "union": UNION, - "unique": UNIQUE, - "unlock": UNUSED, - "unsigned": UNSIGNED, - "update": UPDATE, - "usage": UNUSED, - "use": USE, - "using": USING, - "utc_date": UTC_DATE, - "utc_time": UTC_TIME, - "utc_timestamp": UTC_TIMESTAMP, - "values": VALUES, - "variables": VARIABLES, - "varbinary": VARBINARY, - "varchar": VARCHAR, - "varcharacter": UNUSED, - "varying": UNUSED, - "virtual": UNUSED, - "vindex": VINDEX, - "vindexes": VINDEXES, - "view": VIEW, - "vitess_keyspaces": VITESS_KEYSPACES, - "vitess_shards": VITESS_SHARDS, - "vitess_tablets": VITESS_TABLETS, - "vschema_tables": VSCHEMA_TABLES, - "when": WHEN, - "where": WHERE, - "while": UNUSED, - "with": WITH, - "write": WRITE, - "xor": UNUSED, - "year": YEAR, - "year_month": UNUSED, - "zerofill": ZEROFILL, -} - -// keywordStrings contains the reverse mapping of token to keyword strings -var keywordStrings = map[int]string{} - -func init() { - for str, id := range keywords { - if id == UNUSED { - continue - } - keywordStrings[id] = str - } -} - -// KeywordString returns the string corresponding to the given keyword -func KeywordString(id int) string { - str, ok := keywordStrings[id] - if !ok { - return "" - } - return str -} - -// Lex returns the next token form the Tokenizer. -// This function is used by go yacc. -func (tkn *Tokenizer) Lex(lval *yySymType) int { - typ, val := tkn.Scan() - for typ == COMMENT { - if tkn.AllowComments { - break - } - typ, val = tkn.Scan() - } - lval.bytes = val - tkn.lastToken = val - return typ -} - -// Error is called by go yacc if there's a parsing error. -func (tkn *Tokenizer) Error(err string) { - buf := &bytes2.Buffer{} - if tkn.lastToken != nil { - fmt.Fprintf(buf, "%s at position %v near '%s'", err, tkn.Position, tkn.lastToken) - } else { - fmt.Fprintf(buf, "%s at position %v", err, tkn.Position) - } - tkn.LastError = errors.New(buf.String()) - - // Try and re-sync to the next statement - if tkn.lastChar != ';' { - tkn.skipStatement() - } -} - -// Scan scans the tokenizer for the next token and returns -// the token type and an optional value. -func (tkn *Tokenizer) Scan() (int, []byte) { - if tkn.specialComment != nil { - // Enter specialComment scan mode. - // for scanning such kind of comment: /*! MySQL-specific code */ - specialComment := tkn.specialComment - tok, val := specialComment.Scan() - if tok != 0 { - // return the specialComment scan result as the result - return tok, val - } - // leave specialComment scan mode after all stream consumed. - tkn.specialComment = nil - } - if tkn.lastChar == 0 { - tkn.next() - } - - if tkn.ForceEOF { - tkn.skipStatement() - return 0, nil - } - - tkn.skipBlank() - switch ch := tkn.lastChar; { - case isLetter(ch): - tkn.next() - if ch == 'X' || ch == 'x' { - if tkn.lastChar == '\'' { - tkn.next() - return tkn.scanHex() - } - } - if ch == 'B' || ch == 'b' { - if tkn.lastChar == '\'' { - tkn.next() - return tkn.scanBitLiteral() - } - } - isDbSystemVariable := false - if ch == '@' && tkn.lastChar == '@' { - isDbSystemVariable = true - } - return tkn.scanIdentifier(byte(ch), isDbSystemVariable) - case isDigit(ch): - return tkn.scanNumber(false) - case ch == ':': - return tkn.scanBindVar() - case ch == ';' && tkn.multi: - return 0, nil - default: - tkn.next() - switch ch { - case eofChar: - return 0, nil - case '=', ',', ';', '(', ')', '+', '*', '%', '^', '~': - return int(ch), nil - case '&': - if tkn.lastChar == '&' { - tkn.next() - return AND, nil - } - return int(ch), nil - case '|': - if tkn.lastChar == '|' { - tkn.next() - return OR, nil - } - return int(ch), nil - case '?': - tkn.posVarIndex++ - buf := new(bytes2.Buffer) - fmt.Fprintf(buf, ":v%d", tkn.posVarIndex) - return VALUE_ARG, buf.Bytes() - case '.': - if isDigit(tkn.lastChar) { - return tkn.scanNumber(true) - } - return int(ch), nil - case '/': - switch tkn.lastChar { - case '/': - tkn.next() - return tkn.scanCommentType1("//") - case '*': - tkn.next() - switch tkn.lastChar { - case '!': - return tkn.scanMySQLSpecificComment() - default: - return tkn.scanCommentType2() - } - default: - return int(ch), nil - } - case '#': - return tkn.scanCommentType1("#") - case '-': - switch tkn.lastChar { - case '-': - tkn.next() - return tkn.scanCommentType1("--") - case '>': - tkn.next() - if tkn.lastChar == '>' { - tkn.next() - return JSON_UNQUOTE_EXTRACT_OP, nil - } - return JSON_EXTRACT_OP, nil - } - return int(ch), nil - case '<': - switch tkn.lastChar { - case '>': - tkn.next() - return NE, nil - case '<': - tkn.next() - return SHIFT_LEFT, nil - case '=': - tkn.next() - switch tkn.lastChar { - case '>': - tkn.next() - return NULL_SAFE_EQUAL, nil - default: - return LE, nil - } - default: - return int(ch), nil - } - case '>': - switch tkn.lastChar { - case '=': - tkn.next() - return GE, nil - case '>': - tkn.next() - return SHIFT_RIGHT, nil - default: - return int(ch), nil - } - case '!': - if tkn.lastChar == '=' { - tkn.next() - return NE, nil - } - return int(ch), nil - case '\'', '"': - return tkn.scanString(ch, STRING) - case '`': - return tkn.scanLiteralIdentifier() - default: - return LEX_ERROR, []byte{byte(ch)} - } - } -} - -// skipStatement scans until the EOF, or end of statement is encountered. -func (tkn *Tokenizer) skipStatement() { - ch := tkn.lastChar - for ch != ';' && ch != eofChar { - tkn.next() - ch = tkn.lastChar - } -} - -func (tkn *Tokenizer) skipBlank() { - ch := tkn.lastChar - for ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' { - tkn.next() - ch = tkn.lastChar - } -} - -func (tkn *Tokenizer) scanIdentifier(firstByte byte, isDbSystemVariable bool) (int, []byte) { - buffer := &bytes2.Buffer{} - buffer.WriteByte(firstByte) - for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || (isDbSystemVariable && isCarat(tkn.lastChar)) { - buffer.WriteByte(byte(tkn.lastChar)) - tkn.next() - } - lowered := bytes.ToLower(buffer.Bytes()) - loweredStr := string(lowered) - if keywordID, found := keywords[loweredStr]; found { - return keywordID, lowered - } - // dual must always be case-insensitive - if loweredStr == "dual" { - return ID, lowered - } - return ID, buffer.Bytes() -} - -func (tkn *Tokenizer) scanHex() (int, []byte) { - buffer := &bytes2.Buffer{} - tkn.scanMantissa(16, buffer) - if tkn.lastChar != '\'' { - return LEX_ERROR, buffer.Bytes() - } - tkn.next() - if buffer.Len()%2 != 0 { - return LEX_ERROR, buffer.Bytes() - } - return HEX, buffer.Bytes() -} - -func (tkn *Tokenizer) scanBitLiteral() (int, []byte) { - buffer := &bytes2.Buffer{} - tkn.scanMantissa(2, buffer) - if tkn.lastChar != '\'' { - return LEX_ERROR, buffer.Bytes() - } - tkn.next() - return BIT_LITERAL, buffer.Bytes() -} - -func (tkn *Tokenizer) scanLiteralIdentifier() (int, []byte) { - buffer := &bytes2.Buffer{} - backTickSeen := false - for { - if backTickSeen { - if tkn.lastChar != '`' { - break - } - backTickSeen = false - buffer.WriteByte('`') - tkn.next() - continue - } - // The previous char was not a backtick. - switch tkn.lastChar { - case '`': - backTickSeen = true - case eofChar: - // Premature EOF. - return LEX_ERROR, buffer.Bytes() - default: - buffer.WriteByte(byte(tkn.lastChar)) - } - tkn.next() - } - if buffer.Len() == 0 { - return LEX_ERROR, buffer.Bytes() - } - return ID, buffer.Bytes() -} - -func (tkn *Tokenizer) scanBindVar() (int, []byte) { - buffer := &bytes2.Buffer{} - buffer.WriteByte(byte(tkn.lastChar)) - token := VALUE_ARG - tkn.next() - if tkn.lastChar == ':' { - token = LIST_ARG - buffer.WriteByte(byte(tkn.lastChar)) - tkn.next() - } - if !isLetter(tkn.lastChar) { - return LEX_ERROR, buffer.Bytes() - } - for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || tkn.lastChar == '.' { - buffer.WriteByte(byte(tkn.lastChar)) - tkn.next() - } - return token, buffer.Bytes() -} - -func (tkn *Tokenizer) scanMantissa(base int, buffer *bytes2.Buffer) { - for digitVal(tkn.lastChar) < base { - tkn.consumeNext(buffer) - } -} - -func (tkn *Tokenizer) scanNumber(seenDecimalPoint bool) (int, []byte) { - token := INTEGRAL - buffer := &bytes2.Buffer{} - if seenDecimalPoint { - token = FLOAT - buffer.WriteByte('.') - tkn.scanMantissa(10, buffer) - goto exponent - } - - // 0x construct. - if tkn.lastChar == '0' { - tkn.consumeNext(buffer) - if tkn.lastChar == 'x' || tkn.lastChar == 'X' { - token = HEXNUM - tkn.consumeNext(buffer) - tkn.scanMantissa(16, buffer) - goto exit - } - } - - tkn.scanMantissa(10, buffer) - - if tkn.lastChar == '.' { - token = FLOAT - tkn.consumeNext(buffer) - tkn.scanMantissa(10, buffer) - } - -exponent: - if tkn.lastChar == 'e' || tkn.lastChar == 'E' { - token = FLOAT - tkn.consumeNext(buffer) - if tkn.lastChar == '+' || tkn.lastChar == '-' { - tkn.consumeNext(buffer) - } - tkn.scanMantissa(10, buffer) - } - -exit: - // A letter cannot immediately follow a number. - if isLetter(tkn.lastChar) { - return LEX_ERROR, buffer.Bytes() - } - - return token, buffer.Bytes() -} - -func (tkn *Tokenizer) scanString(delim uint16, typ int) (int, []byte) { - var buffer bytes2.Buffer - for { - ch := tkn.lastChar - if ch == eofChar { - // Unterminated string. - return LEX_ERROR, buffer.Bytes() - } - - if ch != delim && ch != '\\' { - buffer.WriteByte(byte(ch)) - - // Scan ahead to the next interesting character. - start := tkn.bufPos - for ; tkn.bufPos < tkn.bufSize; tkn.bufPos++ { - ch = uint16(tkn.buf[tkn.bufPos]) - if ch == delim || ch == '\\' { - break - } - } - - buffer.Write(tkn.buf[start:tkn.bufPos]) - tkn.Position += (tkn.bufPos - start) - - if tkn.bufPos >= tkn.bufSize { - // Reached the end of the buffer without finding a delim or - // escape character. - tkn.next() - continue - } - - tkn.bufPos++ - tkn.Position++ - } - tkn.next() // Read one past the delim or escape character. - - if ch == '\\' { - if tkn.lastChar == eofChar { - // String terminates mid escape character. - return LEX_ERROR, buffer.Bytes() - } - if decodedChar := sqltypes.SQLDecodeMap[byte(tkn.lastChar)]; decodedChar == sqltypes.DontEscape { - ch = tkn.lastChar - } else { - ch = uint16(decodedChar) - } - - } else if ch == delim && tkn.lastChar != delim { - // Correctly terminated string, which is not a double delim. - break - } - - buffer.WriteByte(byte(ch)) - tkn.next() - } - - return typ, buffer.Bytes() -} - -func (tkn *Tokenizer) scanCommentType1(prefix string) (int, []byte) { - buffer := &bytes2.Buffer{} - buffer.WriteString(prefix) - for tkn.lastChar != eofChar { - if tkn.lastChar == '\n' { - tkn.consumeNext(buffer) - break - } - tkn.consumeNext(buffer) - } - return COMMENT, buffer.Bytes() -} - -func (tkn *Tokenizer) scanCommentType2() (int, []byte) { - buffer := &bytes2.Buffer{} - buffer.WriteString("/*") - for { - if tkn.lastChar == '*' { - tkn.consumeNext(buffer) - if tkn.lastChar == '/' { - tkn.consumeNext(buffer) - break - } - continue - } - if tkn.lastChar == eofChar { - return LEX_ERROR, buffer.Bytes() - } - tkn.consumeNext(buffer) - } - return COMMENT, buffer.Bytes() -} - -func (tkn *Tokenizer) scanMySQLSpecificComment() (int, []byte) { - buffer := &bytes2.Buffer{} - buffer.WriteString("/*!") - tkn.next() - for { - if tkn.lastChar == '*' { - tkn.consumeNext(buffer) - if tkn.lastChar == '/' { - tkn.consumeNext(buffer) - break - } - continue - } - if tkn.lastChar == eofChar { - return LEX_ERROR, buffer.Bytes() - } - tkn.consumeNext(buffer) - } - _, sql := ExtractMysqlComment(buffer.String()) - tkn.specialComment = NewStringTokenizer(sql) - return tkn.Scan() -} - -func (tkn *Tokenizer) consumeNext(buffer *bytes2.Buffer) { - if tkn.lastChar == eofChar { - // This should never happen. - panic("unexpected EOF") - } - buffer.WriteByte(byte(tkn.lastChar)) - tkn.next() -} - -func (tkn *Tokenizer) next() { - if tkn.bufPos >= tkn.bufSize && tkn.InStream != nil { - // Try and refill the buffer - var err error - tkn.bufPos = 0 - if tkn.bufSize, err = tkn.InStream.Read(tkn.buf); err != io.EOF && err != nil { - tkn.LastError = err - } - } - - if tkn.bufPos >= tkn.bufSize { - if tkn.lastChar != eofChar { - tkn.Position++ - tkn.lastChar = eofChar - } - } else { - tkn.Position++ - tkn.lastChar = uint16(tkn.buf[tkn.bufPos]) - tkn.bufPos++ - } -} - -// reset clears any internal state. -func (tkn *Tokenizer) reset() { - tkn.ParseTree = nil - tkn.partialDDL = nil - tkn.specialComment = nil - tkn.posVarIndex = 0 - tkn.nesting = 0 - tkn.ForceEOF = false -} - -func isLetter(ch uint16) bool { - return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch == '@' -} - -func isCarat(ch uint16) bool { - return ch == '.' || ch == '\'' || ch == '"' || ch == '`' -} - -func digitVal(ch uint16) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch) - '0' - case 'a' <= ch && ch <= 'f': - return int(ch) - 'a' + 10 - case 'A' <= ch && ch <= 'F': - return int(ch) - 'A' + 10 - } - return 16 // larger than any legal digit val -} - -func isDigit(ch uint16) bool { - return '0' <= ch && ch <= '9' -} diff --git a/vendor/github.com/xwb1989/sqlparser/tracked_buffer.go b/vendor/github.com/xwb1989/sqlparser/tracked_buffer.go deleted file mode 100644 index ec421a5fb..000000000 --- a/vendor/github.com/xwb1989/sqlparser/tracked_buffer.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2017 Google Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sqlparser - -import ( - "bytes" - "fmt" -) - -// NodeFormatter defines the signature of a custom node formatter -// function that can be given to TrackedBuffer for code generation. -type NodeFormatter func(buf *TrackedBuffer, node SQLNode) - -// TrackedBuffer is used to rebuild a query from the ast. -// bindLocations keeps track of locations in the buffer that -// use bind variables for efficient future substitutions. -// nodeFormatter is the formatting function the buffer will -// use to format a node. By default(nil), it's FormatNode. -// But you can supply a different formatting function if you -// want to generate a query that's different from the default. -type TrackedBuffer struct { - *bytes.Buffer - bindLocations []bindLocation - nodeFormatter NodeFormatter -} - -// NewTrackedBuffer creates a new TrackedBuffer. -func NewTrackedBuffer(nodeFormatter NodeFormatter) *TrackedBuffer { - return &TrackedBuffer{ - Buffer: new(bytes.Buffer), - nodeFormatter: nodeFormatter, - } -} - -// WriteNode function, initiates the writing of a single SQLNode tree by passing -// through to Myprintf with a default format string -func (buf *TrackedBuffer) WriteNode(node SQLNode) *TrackedBuffer { - buf.Myprintf("%v", node) - return buf -} - -// Myprintf mimics fmt.Fprintf(buf, ...), but limited to Node(%v), -// Node.Value(%s) and string(%s). It also allows a %a for a value argument, in -// which case it adds tracking info for future substitutions. -// -// The name must be something other than the usual Printf() to avoid "go vet" -// warnings due to our custom format specifiers. -func (buf *TrackedBuffer) Myprintf(format string, values ...interface{}) { - end := len(format) - fieldnum := 0 - for i := 0; i < end; { - lasti := i - for i < end && format[i] != '%' { - i++ - } - if i > lasti { - buf.WriteString(format[lasti:i]) - } - if i >= end { - break - } - i++ // '%' - switch format[i] { - case 'c': - switch v := values[fieldnum].(type) { - case byte: - buf.WriteByte(v) - case rune: - buf.WriteRune(v) - default: - panic(fmt.Sprintf("unexpected TrackedBuffer type %T", v)) - } - case 's': - switch v := values[fieldnum].(type) { - case []byte: - buf.Write(v) - case string: - buf.WriteString(v) - default: - panic(fmt.Sprintf("unexpected TrackedBuffer type %T", v)) - } - case 'v': - node := values[fieldnum].(SQLNode) - if buf.nodeFormatter == nil { - node.Format(buf) - } else { - buf.nodeFormatter(buf, node) - } - case 'a': - buf.WriteArg(values[fieldnum].(string)) - default: - panic("unexpected") - } - fieldnum++ - i++ - } -} - -// WriteArg writes a value argument into the buffer along with -// tracking information for future substitutions. arg must contain -// the ":" or "::" prefix. -func (buf *TrackedBuffer) WriteArg(arg string) { - buf.bindLocations = append(buf.bindLocations, bindLocation{ - offset: buf.Len(), - length: len(arg), - }) - buf.WriteString(arg) -} - -// ParsedQuery returns a ParsedQuery that contains bind -// locations for easy substitution. -func (buf *TrackedBuffer) ParsedQuery() *ParsedQuery { - return &ParsedQuery{Query: buf.String(), bindLocations: buf.bindLocations} -} - -// HasBindVars returns true if the parsed query uses bind vars. -func (buf *TrackedBuffer) HasBindVars() bool { - return len(buf.bindLocations) != 0 -} - -// BuildParsedQuery builds a ParsedQuery from the input. -func BuildParsedQuery(in string, vars ...interface{}) *ParsedQuery { - buf := NewTrackedBuffer(nil) - buf.Myprintf(in, vars...) - return buf.ParsedQuery() -} diff --git a/vendor/vendor.json b/vendor/vendor.json index d28378dde..2ef0b9c31 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -97,6 +97,18 @@ "revision": "f6be1abbb5abd0517522f850dd785990d373da7e", "revisionTime": "2017-09-13T22:19:17Z" }, + { + "checksumSHA1": "Xmp7mYQyG/1fyIahOyTyN9yZamY=", + "path": "github.com/alecthomas/participle", + "revision": "bf8340a459bd383e5eb7d44a9a1b3af23b6cf8cd", + "revisionTime": "2019-01-03T08:53:15Z" + }, + { + "checksumSHA1": "0R8Lqt4DtU8+7Eq1mL7Hd+cjDOI=", + "path": "github.com/alecthomas/participle/lexer", + "revision": "bf8340a459bd383e5eb7d44a9a1b3af23b6cf8cd", + "revisionTime": "2019-01-03T08:53:15Z" + }, { "checksumSHA1": "tX0Bq1gzqskL98nnB1X2rDqxH18=", "path": "github.com/aliyun/aliyun-oss-go-sdk/oss", @@ -644,10 +656,10 @@ "revisionTime": "2019-01-20T10:05:29Z" }, { - "checksumSHA1": "pxgHNx36gpRdhSqtaE5fqp7lrAA=", + "checksumSHA1": "ik77jlf0oMQTlSndP85DlIVOnOY=", "path": "github.com/minio/parquet-go", - "revision": "1014bfb4d0e323e3fbf6683e3519a98b0721f5cc", - "revisionTime": "2019-01-14T09:43:57Z" + "revision": "7a17a919eeed02c393f3117a9ed1ac6df0da9aa5", + "revisionTime": "2019-01-18T04:40:39Z" }, { "checksumSHA1": "N4WRPw4p3AN958RH/O53kUsJacQ=", @@ -888,12 +900,6 @@ "revision": "ceec8f93295a060cdb565ec25e4ccf17941dbd55", "revisionTime": "2016-11-14T21:01:44Z" }, - { - "checksumSHA1": "6ksZHYhLc3yOzTbcWKb3bDENhD4=", - "path": "github.com/xwb1989/sqlparser", - "revision": "120387863bf27d04bc07db8015110a6e96d0146c", - "revisionTime": "2018-06-06T15:21:19Z" - }, { "checksumSHA1": "L/Q8Ylbo+wnj5whDFfMxxwyxmdo=", "path": "github.com/xwb1989/sqlparser/dependency/bytes2",