Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions go/cmd/dolt/commands/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1138,10 +1138,67 @@ func processQuery(ctx *sql.Context, query string, qryist cli.Queryist) (sql.Sche
return processParsedQuery(ctx, query, qryist, sqlStatement)
}

func cleanCommentedSelectExpressionNames(sqlStatement sqlparser.Statement) {
if sqlStatement == nil {
return
}
_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
aliasedExpr, ok := node.(*sqlparser.AliasedExpr)
if ok && aliasedExpr.As.IsEmpty() && containsSQLComment(aliasedExpr.InputExpression) {
aliasedExpr.InputExpression = ""
}
return true, nil
}, sqlStatement)
}

func containsSQLComment(s string) bool {
var quote byte
for i := 0; i < len(s); i++ {
c := s[i]
if quote != 0 {
if c == '\\' && quote != '`' {
i++
continue
}
if c == quote {
quote = 0
}
continue
}

switch c {
case '\'', '"', '`':
quote = c
case '#':
return true
case '-':
if i+1 < len(s) && s[i+1] == '-' && (i+2 == len(s) || isSQLWhitespace(s[i+2])) {
return true
}
case '/':
if i+1 < len(s) && s[i+1] == '*' {
return true
}
}
}
return false
}

func isSQLWhitespace(c byte) bool {
switch c {
case ' ', '\t', '\n', '\r', '\f', '\v':
return true
default:
return false
}
}

// processParsedQuery processes a single query with the parsed statement provided. The Root of the sqlEngine
// will be updated if necessary. Returns the schema and the row iterator for the results, which may be nil,
// and an error if one occurs.
func processParsedQuery(ctx *sql.Context, query string, qryist cli.Queryist, sqlStatement sqlparser.Statement) (sql.Schema, sql.RowIter, *sql.QueryFlags, error) {
cleanCommentedSelectExpressionNames(sqlStatement)

switch s := sqlStatement.(type) {
case *sqlparser.Use, *sqlparser.Commit:
_, ri, _, err := qryist.Query(ctx, query)
Expand Down
49 changes: 49 additions & 0 deletions go/cmd/dolt/commands/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"testing"

"github.com/dolthub/go-mysql-server/sql"
_ "github.com/dolthub/go-mysql-server/sql/variables"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -93,6 +94,54 @@ func TestSqlBatchMode(t *testing.T) {
}
}

func TestSqlLiteralColumnNamesIgnoreTrailingLineComments(t *testing.T) {
tests := []struct {
query string
expectedNames []string
expectedRows []sql.Row
}{
{
query: "select null -- comment",
expectedNames: []string{"NULL"},
expectedRows: []sql.Row{{nil}},
},
{
query: "select 1, -- one\n2 -- two",
expectedNames: []string{"1", "2"},
expectedRows: []sql.Row{{int8(1), int8(2)}},
},
{
query: "select \"string\", -- string\n\"another string\" -- another string",
expectedNames: []string{"string", "another string"},
expectedRows: []sql.Row{{"string", "another string"}},
},
}

for _, test := range tests {
t.Run(test.query, func(t *testing.T) {
ctx := t.Context()
dEnv := DEnvWithSeedDataForTest(ctx, t)
cliCtx := NewArgFreeCliContextForTest(ctx, t, dEnv)

queryEngine, err := cliCtx.QueryEngine(ctx)
require.NoError(t, err)

sqlSch, rowIter, _, err := processQuery(queryEngine.Context, test.query, queryEngine.Queryist)
require.NoError(t, err)
require.NotNil(t, rowIter)

rows, err := sql.RowIterToRows(queryEngine.Context, rowIter)
require.NoError(t, err)
require.Equal(t, test.expectedRows, rows)

require.Len(t, sqlSch, len(test.expectedNames))
for i, expectedName := range test.expectedNames {
require.Equal(t, expectedName, sqlSch[i].Name)
}
})
}
}

// Smoke tests, values are printed to console
func TestSqlSelect(t *testing.T) {
tests := []struct {
Expand Down
Loading