mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Attributes are unmaintained and unused. They have become more of a liability than a benefit. This change eliminates them from the codebase. The only user-visible change (assuming that attrs are not used) is that the attrs field will no longer appear in row JSON.
113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
// Copyright 2020 Pilosa Corp.
|
|
//
|
|
// 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/pilosa/pilosa/v2/logger"
|
|
"github.com/pkg/errors"
|
|
"vitess.io/vitess/go/vt/sqlparser"
|
|
)
|
|
|
|
const (
|
|
SQLTypeSelect = "select"
|
|
SQLTypeShow = "show"
|
|
SQLTypeEmpty = ""
|
|
)
|
|
|
|
// System errors.
|
|
var (
|
|
ErrMultipleSQLStatements = errors.New("statement contains multiple sql queries")
|
|
)
|
|
|
|
type MappedSQL struct {
|
|
SQLType string
|
|
Statement sqlparser.Statement
|
|
Mask QueryMask
|
|
Tables []string
|
|
SQL string
|
|
}
|
|
|
|
// Mapper is responsible for mapping a SQL query to structure representation
|
|
type Mapper struct {
|
|
Logger logger.Logger
|
|
}
|
|
|
|
func NewMapper() *Mapper {
|
|
return &Mapper{
|
|
Logger: logger.NopLogger,
|
|
}
|
|
}
|
|
|
|
// Parse parses SQL query
|
|
func (m *Mapper) Parse(sql string) (sqlparser.Statement, QueryMask, error) {
|
|
parsed, err := sqlparser.Parse(sql)
|
|
if err != nil {
|
|
return nil, QueryMask{}, errors.Wrap(err, "parsing sql")
|
|
}
|
|
|
|
qm := GenerateMask(parsed)
|
|
|
|
return parsed, qm, nil
|
|
}
|
|
|
|
// MapSQL converts a sql string into a MappedSQL object,
|
|
// which includes the parsed query and the query mask,
|
|
// among other information about the query.
|
|
func (m *Mapper) MapSQL(sql string) (*MappedSQL, error) {
|
|
// In the case where `sql` contains more than one query—since
|
|
// we don't support multiple return sets—we're going to just
|
|
// ignore everything and return a specific error type. This
|
|
// will allow the caller to handle it as needed (i.e. it can
|
|
// return the error, or return an empty result set).
|
|
if parts := strings.Split(sql, ";"); len(parts) > 1 {
|
|
var partCount int
|
|
for _, part := range parts {
|
|
if trimmed := strings.TrimSpace(part); trimmed != "" && trimmed != "\x00" {
|
|
partCount++
|
|
}
|
|
}
|
|
if partCount != 1 {
|
|
return nil, ErrMultipleSQLStatements
|
|
}
|
|
}
|
|
|
|
stmt, qm, err := m.Parse(sql)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "parsing sql")
|
|
}
|
|
|
|
var sqlType string
|
|
var tableNames []string
|
|
switch slct := stmt.(type) {
|
|
case *sqlparser.Select:
|
|
sqlType = SQLTypeSelect
|
|
tableNames, err = extractTableNames(slct)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "extracting table names")
|
|
}
|
|
case *sqlparser.Show:
|
|
sqlType = SQLTypeShow
|
|
}
|
|
|
|
return &MappedSQL{
|
|
SQLType: sqlType,
|
|
Statement: stmt,
|
|
Mask: qm,
|
|
Tables: tableNames,
|
|
SQL: sql,
|
|
}, nil
|
|
}
|