837 lines
20 KiB
Go
837 lines
20 KiB
Go
package parser
|
|
|
|
// #include "query_types.h"
|
|
// #include <stdlib.h>
|
|
import "C"
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
type From struct {
|
|
TableName string
|
|
}
|
|
|
|
type Operation int
|
|
|
|
type IntoClause struct {
|
|
Target *Value
|
|
Backfill bool
|
|
BackfillValue *Value
|
|
}
|
|
|
|
type BasicQuery struct {
|
|
startTime time.Time
|
|
endTime time.Time
|
|
startTimeSpecified bool
|
|
}
|
|
|
|
type SelectDeleteCommonQuery struct {
|
|
BasicQuery
|
|
FromClause *FromClause
|
|
Condition *WhereCondition
|
|
}
|
|
|
|
type SelectQuery struct {
|
|
SelectDeleteCommonQuery
|
|
ColumnNames []*Value
|
|
groupByClause *GroupByClause
|
|
IntoClause *IntoClause
|
|
Limit int
|
|
Ascending bool
|
|
Explain bool
|
|
}
|
|
|
|
type ListType int
|
|
|
|
const (
|
|
Series ListType = iota
|
|
ContinuousQueries
|
|
SeriesWithRegex
|
|
)
|
|
|
|
type ListQuery struct {
|
|
Type ListType
|
|
value *Value
|
|
IncludeSpaces bool
|
|
}
|
|
|
|
type DropQuery struct {
|
|
Id int
|
|
}
|
|
|
|
type DropSeriesQuery struct {
|
|
tableName string
|
|
}
|
|
|
|
func (self *DropSeriesQuery) GetTableName() string {
|
|
return self.tableName
|
|
}
|
|
|
|
type DeleteQuery struct {
|
|
SelectDeleteCommonQuery
|
|
}
|
|
|
|
type Query struct {
|
|
SelectQuery *SelectQuery
|
|
DeleteQuery *DeleteQuery
|
|
ListQuery *ListQuery
|
|
DropSeriesQuery *DropSeriesQuery
|
|
DropQuery *DropQuery
|
|
qType QueryType
|
|
}
|
|
|
|
func (self *IntoClause) GetString() string {
|
|
buffer := bytes.NewBufferString("")
|
|
|
|
buffer.WriteString(self.Target.GetString())
|
|
if self.BackfillValue != nil {
|
|
fmt.Fprintf(buffer, " backfill(%s)", self.BackfillValue.GetString())
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
func (self *Query) Type() QueryType {
|
|
return self.qType
|
|
}
|
|
|
|
func (self *Query) GetQueryString() string {
|
|
return self.commonGetQueryString(false)
|
|
}
|
|
|
|
func (self *Query) GetQueryStringWithTimeCondition() string {
|
|
return self.commonGetQueryString(true)
|
|
}
|
|
|
|
func (self *Query) commonGetQueryString(withTime bool) string {
|
|
switch self.qType {
|
|
case Select, Continuous:
|
|
if withTime {
|
|
return self.SelectQuery.GetQueryStringWithTimeCondition()
|
|
}
|
|
return self.SelectQuery.GetQueryString()
|
|
case Delete:
|
|
return self.DeleteQuery.GetQueryString(withTime)
|
|
case DropContinuousQuery:
|
|
return fmt.Sprintf("drop continuous query %d", self.DropQuery.Id)
|
|
case ListSeries:
|
|
return "list series"
|
|
case ListContinuousQueries:
|
|
return "list continuous queries"
|
|
case DropSeries:
|
|
return "drop series " + self.DropSeriesQuery.tableName
|
|
default:
|
|
panic(fmt.Errorf("Unknown query type %s", self.qType))
|
|
}
|
|
}
|
|
|
|
func (self *Query) IsListQuery() bool {
|
|
return self.ListQuery != nil
|
|
}
|
|
|
|
func (self *Query) IsExplainQuery() bool {
|
|
return self.SelectQuery != nil && self.SelectQuery.Explain
|
|
}
|
|
|
|
func (self *Query) GetListSeriesQuery() *ListQuery {
|
|
return self.ListQuery
|
|
}
|
|
|
|
func (self *Query) IsListSeriesQuery() bool {
|
|
return self.ListQuery != nil && (self.ListQuery.Type == Series || self.ListQuery.Type == SeriesWithRegex)
|
|
}
|
|
|
|
func (self *Query) IsListContinuousQueriesQuery() bool {
|
|
return self.ListQuery != nil && self.ListQuery.Type == ContinuousQueries
|
|
}
|
|
|
|
func (self *ListQuery) HasRegex() bool {
|
|
return self.Type == SeriesWithRegex
|
|
}
|
|
|
|
func (self *ListQuery) IsCaseSensitive() bool {
|
|
return self.value.IsInsensitive
|
|
}
|
|
|
|
func (self *ListQuery) GetRegex() *regexp.Regexp {
|
|
regex, _ := self.value.GetCompiledRegex()
|
|
return regex
|
|
}
|
|
|
|
func (self *DeleteQuery) GetQueryString(withTime bool) string {
|
|
buffer := bytes.NewBufferString("delete ")
|
|
fmt.Fprintf(buffer, "from %s", self.FromClause.GetString())
|
|
if withTime {
|
|
fmt.Fprintf(buffer, " where %s", self.GetWhereConditionWithTime(self.startTime, self.endTime).GetString())
|
|
} else if condition := self.GetWhereCondition(); condition != nil {
|
|
fmt.Fprintf(buffer, " where %s", condition.GetString())
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
func (self *SelectQuery) GetColumnNames() []*Value {
|
|
return self.ColumnNames
|
|
}
|
|
|
|
func (self *SelectQuery) IsExplainQuery() bool {
|
|
return self.Explain
|
|
}
|
|
|
|
func (self *SelectQuery) GetQueryString() string {
|
|
return self.commonGetQueryStringWithTimes(false, true, self.startTime, self.endTime)
|
|
}
|
|
|
|
func (self *SelectQuery) GetQueryStringWithTimeCondition() string {
|
|
// if this is a single point query then it already has a time (and
|
|
// sequence number) condition; we don't need the extra (time < ???
|
|
// and time > ???) condition in the query string.
|
|
if self.IsSinglePointQuery() {
|
|
return self.GetQueryString()
|
|
}
|
|
|
|
return self.commonGetQueryStringWithTimes(true, true, self.startTime, self.endTime)
|
|
}
|
|
|
|
func (self *SelectQuery) GetQueryStringWithTimes(startTime, endTime time.Time) string {
|
|
return self.commonGetQueryStringWithTimes(true, true, startTime, endTime)
|
|
}
|
|
|
|
func (self *SelectQuery) GetQueryStringWithTimesAndNoIntoClause(startTime, endTime time.Time) string {
|
|
return self.commonGetQueryStringWithTimes(true, false, startTime, endTime)
|
|
}
|
|
|
|
func (self *SelectQuery) commonGetQueryStringWithTimes(withTime, withIntoClause bool, startTime, endTime time.Time) string {
|
|
buffer := bytes.NewBufferString("")
|
|
fmt.Fprintf(buffer, "select ")
|
|
|
|
buffer.WriteString(Values(self.ColumnNames).GetString())
|
|
|
|
fmt.Fprintf(buffer, " from %s", self.FromClause.GetString())
|
|
if withTime {
|
|
fmt.Fprintf(buffer, " where %s", self.GetWhereConditionWithTime(startTime, endTime).GetString())
|
|
} else if condition := self.GetWhereCondition(); condition != nil {
|
|
fmt.Fprintf(buffer, " where %s", condition.GetString())
|
|
}
|
|
if self.GetGroupByClause() != nil && len(self.GetGroupByClause().Elems) > 0 {
|
|
fmt.Fprintf(buffer, " group by %s", self.GetGroupByClause().GetString())
|
|
}
|
|
|
|
if self.Limit > 0 {
|
|
fmt.Fprintf(buffer, " limit %d", self.Limit)
|
|
}
|
|
|
|
if self.Ascending {
|
|
fmt.Fprintf(buffer, " order asc")
|
|
}
|
|
|
|
if clause := self.IntoClause; withIntoClause && clause != nil {
|
|
fmt.Fprintf(buffer, " into %s", clause.GetString())
|
|
}
|
|
|
|
return buffer.String()
|
|
}
|
|
|
|
func (self *SelectQuery) IsSinglePointQuery() bool {
|
|
w := self.GetWhereCondition()
|
|
if w == nil {
|
|
return false
|
|
}
|
|
|
|
leftWhereCondition, ok := w.GetLeftWhereCondition()
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
leftBoolExpression, ok := leftWhereCondition.GetBoolExpression()
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
rightBoolExpression, ok := w.Right.GetBoolExpression()
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if leftBoolExpression.Name != "=" && rightBoolExpression.Name != "=" {
|
|
return false
|
|
}
|
|
|
|
if leftBoolExpression.Elems[0].Name != "time" || rightBoolExpression.Elems[0].Name != "sequence_number" {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (self *SelectQuery) GetSinglePointQuerySequenceNumber() (uint64, error) {
|
|
w := self.GetWhereCondition()
|
|
rightBoolExpression, _ := w.Right.GetBoolExpression()
|
|
sequence := rightBoolExpression.Elems[1].Name
|
|
sequence_number, err := strconv.ParseUint(sequence, 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("The column sequence_number can only be queried as an integer.")
|
|
}
|
|
return sequence_number, nil
|
|
}
|
|
|
|
func (self *Query) IsContinuousQuery() bool {
|
|
return self.qType == Continuous
|
|
}
|
|
|
|
func (self *SelectQuery) IsValidContinuousQuery() bool {
|
|
groupByClause := self.GetGroupByClause()
|
|
|
|
if len(groupByClause.Elems) == 0 {
|
|
return true
|
|
}
|
|
|
|
for _, elem := range groupByClause.Elems {
|
|
if elem.Name == "time" {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (self *SelectQuery) IsNonRecursiveContinuousQuery() bool {
|
|
fromClause := self.GetFromClause()
|
|
intoClause := self.GetIntoClause()
|
|
|
|
for _, from := range fromClause.Names {
|
|
regex, ok := from.Name.GetCompiledRegex()
|
|
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
regexString := regex.String()
|
|
intoTarget := intoClause.Target.Name
|
|
|
|
if !strings.Contains(intoTarget, ":series_name") {
|
|
continue
|
|
} else {
|
|
if strings.HasPrefix(regexString, "^") && !strings.HasPrefix(intoTarget, ":series_name") {
|
|
continue
|
|
}
|
|
|
|
if strings.HasSuffix(regexString, "$") && !strings.HasSuffix(intoTarget, ":series_name") {
|
|
continue
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (self *SelectQuery) GetIntoClause() *IntoClause {
|
|
return self.IntoClause
|
|
}
|
|
|
|
func (self *SelectDeleteCommonQuery) GetFromClause() *FromClause {
|
|
return self.FromClause
|
|
}
|
|
|
|
func setupSlice(hdr *reflect.SliceHeader, ptr unsafe.Pointer, size C.size_t) {
|
|
hdr.Cap = int(size)
|
|
hdr.Len = int(size)
|
|
hdr.Data = uintptr(ptr)
|
|
}
|
|
|
|
func GetGroupByClause(groupByClause *C.groupby_clause) (*GroupByClause, error) {
|
|
if groupByClause == nil {
|
|
return &GroupByClause{Elems: nil}, nil
|
|
}
|
|
|
|
values, err := GetValueArray((*C.value_array)(groupByClause.elems))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fillWithZero := false
|
|
var fillValue *Value
|
|
|
|
if groupByClause.fill_function != nil {
|
|
fun, err := GetValue(groupByClause.fill_function)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if fun.Name != "fill" {
|
|
return nil, fmt.Errorf("You can't use %s with group by", fun.Name)
|
|
}
|
|
|
|
if len(fun.Elems) != 1 {
|
|
return nil, fmt.Errorf("`fill` accepts one argument only")
|
|
}
|
|
|
|
fillValue = fun.Elems[0]
|
|
fillWithZero = true
|
|
}
|
|
|
|
return &GroupByClause{
|
|
Elems: values,
|
|
FillWithZero: fillWithZero,
|
|
FillValue: fillValue,
|
|
}, nil
|
|
}
|
|
|
|
func GetValueArray(array *C.value_array) ([]*Value, error) {
|
|
if array == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
var values []*C.value
|
|
setupSlice((*reflect.SliceHeader)((unsafe.Pointer(&values))), unsafe.Pointer(array.elems), array.size)
|
|
|
|
valuesSlice := make([]*Value, 0, array.size)
|
|
|
|
for _, value := range values {
|
|
value, err := GetValue(value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
valuesSlice = append(valuesSlice, value)
|
|
}
|
|
return valuesSlice, nil
|
|
}
|
|
|
|
func GetStringArray(array *C.array) []string {
|
|
if array == nil {
|
|
return nil
|
|
}
|
|
|
|
var values []*C.char
|
|
setupSlice((*reflect.SliceHeader)((unsafe.Pointer(&values))), unsafe.Pointer(array.elems), array.size)
|
|
|
|
stringSlice := make([]string, 0, array.size)
|
|
|
|
for _, value := range values {
|
|
stringSlice = append(stringSlice, C.GoString(value))
|
|
}
|
|
return stringSlice
|
|
}
|
|
|
|
func GetValue(value *C.value) (*Value, error) {
|
|
v := &Value{}
|
|
v.Name = C.GoString(value.name)
|
|
var err error
|
|
v.Elems, err = GetValueArray((*C.value_array)(value.args))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
v.Type = ValueType(value.value_type)
|
|
isCaseInsensitive := value.is_case_insensitive != 0
|
|
if v.Type == ValueRegex {
|
|
if isCaseInsensitive {
|
|
v.compiledRegex, err = regexp.Compile("(?i)" + v.Name)
|
|
} else {
|
|
v.compiledRegex, err = regexp.Compile(v.Name)
|
|
}
|
|
v.IsInsensitive = isCaseInsensitive
|
|
}
|
|
if value.alias != nil {
|
|
v.Alias = C.GoString(value.alias)
|
|
}
|
|
return v, err
|
|
}
|
|
|
|
func GetTableName(name *C.table_name) (*TableName, error) {
|
|
value, err := GetValue(name.name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
table := &TableName{Name: value}
|
|
if name.alias != nil {
|
|
table.Alias = C.GoString(name.alias)
|
|
}
|
|
|
|
return table, nil
|
|
}
|
|
|
|
func GetTableNameArray(array *C.table_name_array) ([]*TableName, error) {
|
|
var names []*C.table_name
|
|
setupSlice((*reflect.SliceHeader)((unsafe.Pointer(&names))), unsafe.Pointer(array.elems), array.size)
|
|
|
|
tableNamesSlice := make([]*TableName, 0, array.size)
|
|
for _, name := range names {
|
|
tableName, err := GetTableName(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tableNamesSlice = append(tableNamesSlice, tableName)
|
|
}
|
|
return tableNamesSlice, nil
|
|
}
|
|
|
|
func GetFromClause(fromClause *C.from_clause) (*FromClause, error) {
|
|
t := FromClauseType(fromClause.from_clause_type)
|
|
var arr []*TableName
|
|
var regex *regexp.Regexp
|
|
|
|
switch t {
|
|
case FromClauseMergeRegex, FromClauseJoinRegex:
|
|
val, err := GetValue(fromClause.regex_value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if val.Type != ValueRegex {
|
|
return nil, fmt.Errorf("merge() accepts regex only")
|
|
}
|
|
regex = val.compiledRegex
|
|
default:
|
|
var err error
|
|
arr, err = GetTableNameArray(fromClause.names)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &FromClause{t, arr, regex}, nil
|
|
}
|
|
|
|
func GetIntoClause(intoClause *C.into_clause) (*IntoClause, error) {
|
|
if intoClause == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
backfill := true
|
|
var backfillValue *Value = nil
|
|
|
|
target, err := GetValue(intoClause.target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if intoClause.backfill_function != nil {
|
|
fun, err := GetValue(intoClause.backfill_function)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if fun.Name != "backfill" {
|
|
return nil, fmt.Errorf("You can't use %s with into", fun.Name)
|
|
}
|
|
|
|
if len(fun.Elems) != 1 {
|
|
return nil, fmt.Errorf("`backfill` accepts only one argument")
|
|
}
|
|
|
|
backfillValue = fun.Elems[0]
|
|
backfill, err = strconv.ParseBool(backfillValue.GetString())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("`backfill` accepts only bool arguments")
|
|
}
|
|
}
|
|
|
|
return &IntoClause{
|
|
Target: target,
|
|
Backfill: backfill,
|
|
BackfillValue: backfillValue,
|
|
}, nil
|
|
}
|
|
|
|
func GetWhereCondition(condition *C.condition) (*WhereCondition, error) {
|
|
if condition.is_bool_expression != 0 {
|
|
expr, err := GetValue((*C.value)(condition.left))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &WhereCondition{
|
|
isBooleanExpression: true,
|
|
Left: expr,
|
|
Operation: "",
|
|
Right: nil,
|
|
}, nil
|
|
}
|
|
|
|
c := &WhereCondition{}
|
|
var err error
|
|
c.Left, err = GetWhereCondition((*C.condition)(condition.left))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c.Operation = C.GoString(condition.op)
|
|
c.Right, err = GetWhereCondition((*C.condition)(unsafe.Pointer(condition.right)))
|
|
|
|
return c, err
|
|
}
|
|
|
|
func (self *SelectDeleteCommonQuery) GetWhereCondition() *WhereCondition {
|
|
return self.Condition
|
|
}
|
|
|
|
func (self *SelectDeleteCommonQuery) GetWhereConditionWithTime(startTime, endTime time.Time) *WhereCondition {
|
|
timeCondition := &WhereCondition{
|
|
isBooleanExpression: false,
|
|
Operation: "AND",
|
|
Left: &WhereCondition{
|
|
isBooleanExpression: true,
|
|
Left: &Value{
|
|
Name: "<",
|
|
Type: ValueExpression,
|
|
Elems: []*Value{
|
|
{Name: "time", Type: ValueSimpleName},
|
|
{Name: strconv.FormatInt(endTime.UnixNano(), 10), Type: ValueInt},
|
|
},
|
|
},
|
|
},
|
|
Right: &WhereCondition{
|
|
isBooleanExpression: true,
|
|
Left: &Value{
|
|
Name: ">",
|
|
Type: ValueExpression,
|
|
Elems: []*Value{
|
|
{Name: "time", Type: ValueSimpleName},
|
|
{Name: strconv.FormatInt(startTime.UnixNano(), 10), Type: ValueInt},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if self.Condition == nil {
|
|
return timeCondition
|
|
}
|
|
|
|
return &WhereCondition{
|
|
isBooleanExpression: false,
|
|
Left: self.Condition,
|
|
Right: timeCondition,
|
|
Operation: "AND",
|
|
}
|
|
|
|
}
|
|
|
|
func (self *SelectQuery) GetGroupByClause() *GroupByClause {
|
|
return self.groupByClause
|
|
}
|
|
|
|
// This is just for backward compatability so we don't have
|
|
// to change all the code.
|
|
func ParseSelectQuery(query string) (*SelectQuery, error) {
|
|
queries, err := ParseQuery(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(queries) == 0 {
|
|
return nil, fmt.Errorf("No queries found")
|
|
}
|
|
|
|
selectQuery := queries[0].SelectQuery
|
|
if selectQuery == nil {
|
|
return nil, fmt.Errorf("Query isn't a select query: '%s'", queries[0].GetQueryString())
|
|
}
|
|
|
|
return selectQuery, nil
|
|
}
|
|
|
|
func parseSingleQuery(q *C.query) (*Query, error) {
|
|
if q.list_series_query != nil {
|
|
var value *Value
|
|
var err error
|
|
t := Series
|
|
if q.list_series_query.has_regex != 0 {
|
|
t = SeriesWithRegex
|
|
value, err = GetValue(q.list_series_query.regex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
includeSpaces := false
|
|
if q.list_series_query.include_spaces != 0 {
|
|
includeSpaces = true
|
|
}
|
|
return &Query{ListQuery: &ListQuery{Type: t, value: value, IncludeSpaces: includeSpaces}, qType: ListSeries}, nil
|
|
}
|
|
|
|
if q.list_continuous_queries_query != 0 {
|
|
return &Query{ListQuery: &ListQuery{Type: ContinuousQueries}, qType: ListContinuousQueries}, nil
|
|
}
|
|
|
|
if q.select_query != nil {
|
|
selectQuery, err := parseSelectQuery(q.select_query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
qType := Select
|
|
if selectQuery.IntoClause != nil {
|
|
qType = Continuous
|
|
}
|
|
return &Query{SelectQuery: selectQuery, qType: qType}, nil
|
|
} else if q.delete_query != nil {
|
|
deleteQuery, err := parseDeleteQuery(q.delete_query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Query{DeleteQuery: deleteQuery, qType: Delete}, nil
|
|
} else if q.drop_series_query != nil {
|
|
dropSeriesQuery, err := parseDropSeriesQuery(q.drop_series_query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Query{DropSeriesQuery: dropSeriesQuery, qType: DropSeries}, nil
|
|
} else if q.drop_query != nil {
|
|
return &Query{DropQuery: &DropQuery{Id: int(q.drop_query.id)}, qType: DropContinuousQuery}, nil
|
|
}
|
|
return nil, fmt.Errorf("Unknown query type encountered")
|
|
}
|
|
|
|
func ParseQuery(queryStr string) ([]*Query, error) {
|
|
queryString := C.CString(queryStr)
|
|
defer C.free(unsafe.Pointer(queryString))
|
|
q := C.parse_query(queryString)
|
|
defer C.close_queries(&q)
|
|
|
|
if q.error != nil {
|
|
str := C.GoString(q.error.err)
|
|
return nil, &QueryError{
|
|
firstLine: int(q.error.first_line),
|
|
firstColumn: int(q.error.first_column) - 1,
|
|
lastLine: int(q.error.last_line),
|
|
lastColumn: int(q.error.last_column) - 1,
|
|
errorString: str,
|
|
queryString: queryStr,
|
|
}
|
|
}
|
|
|
|
var queries []*C.query
|
|
setupSlice((*reflect.SliceHeader)((unsafe.Pointer(&queries))), unsafe.Pointer(q.qs), q.size)
|
|
|
|
parsedQueries := make([]*Query, len(queries))
|
|
for i, query := range queries {
|
|
query, err := parseSingleQuery(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
parsedQueries[i] = query
|
|
}
|
|
return parsedQueries, nil
|
|
}
|
|
|
|
func parseDropSeriesQuery(dropSeriesQuery *C.drop_series_query) (*DropSeriesQuery, error) {
|
|
name, err := GetValue(dropSeriesQuery.name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &DropSeriesQuery{
|
|
tableName: name.Name,
|
|
}, nil
|
|
}
|
|
|
|
func parseSelectDeleteCommonQuery(fromClause *C.from_clause, whereCondition *C.condition) (SelectDeleteCommonQuery, error) {
|
|
|
|
goQuery := SelectDeleteCommonQuery{
|
|
BasicQuery: BasicQuery{
|
|
startTime: time.Unix(math.MinInt64/1000000000, 0).UTC(),
|
|
endTime: time.Now().UTC(),
|
|
},
|
|
}
|
|
|
|
var err error
|
|
|
|
// get the from clause
|
|
goQuery.FromClause, err = GetFromClause(fromClause)
|
|
if err != nil {
|
|
return goQuery, err
|
|
}
|
|
|
|
// get the where condition
|
|
if whereCondition != nil {
|
|
goQuery.Condition, err = GetWhereCondition(whereCondition)
|
|
if err != nil {
|
|
return goQuery, err
|
|
}
|
|
}
|
|
|
|
var startTime, endTime *time.Time
|
|
goQuery.Condition, endTime, err = getTime(goQuery.GetWhereCondition(), false)
|
|
if err != nil {
|
|
return goQuery, err
|
|
}
|
|
|
|
if endTime != nil {
|
|
goQuery.endTime = *endTime
|
|
}
|
|
|
|
goQuery.Condition, startTime, err = getTime(goQuery.GetWhereCondition(), true)
|
|
if err != nil {
|
|
return goQuery, err
|
|
}
|
|
|
|
if startTime != nil {
|
|
goQuery.startTime = *startTime
|
|
goQuery.startTimeSpecified = true
|
|
}
|
|
|
|
return goQuery, nil
|
|
}
|
|
|
|
func parseSelectQuery(q *C.select_query) (*SelectQuery, error) {
|
|
limit := q.limit
|
|
if limit == -1 {
|
|
// no limit by default
|
|
limit = 0
|
|
}
|
|
|
|
basicQuery, err := parseSelectDeleteCommonQuery(q.from_clause, q.where_condition)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
goQuery := &SelectQuery{
|
|
SelectDeleteCommonQuery: basicQuery,
|
|
Limit: int(limit),
|
|
Ascending: q.ascending != 0,
|
|
Explain: q.explain != 0,
|
|
}
|
|
|
|
// get the column names
|
|
goQuery.ColumnNames, err = GetValueArray((*C.value_array)(q.c))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// get the group by clause
|
|
if q.group_by == nil {
|
|
goQuery.groupByClause = &GroupByClause{}
|
|
} else {
|
|
goQuery.groupByClause, err = GetGroupByClause(q.group_by)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// get the into clause
|
|
goQuery.IntoClause, err = GetIntoClause(q.into_clause)
|
|
if err != nil {
|
|
return goQuery, err
|
|
}
|
|
|
|
return goQuery, nil
|
|
}
|
|
|
|
func parseDeleteQuery(query *C.delete_query) (*DeleteQuery, error) {
|
|
basicQuery, err := parseSelectDeleteCommonQuery(query.from_clause, query.where_condition)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
goQuery := &DeleteQuery{
|
|
SelectDeleteCommonQuery: basicQuery,
|
|
}
|
|
if basicQuery.GetWhereCondition() != nil {
|
|
return nil, fmt.Errorf("Delete queries can't have where clause that don't reference time")
|
|
}
|
|
return goQuery, nil
|
|
}
|