Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
mithrandie committed Jun 22, 2017
2 parents 766b88c + 30bc1f5 commit fbf736d
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 32 deletions.
1 change: 1 addition & 0 deletions docs/_posts/2006-01-02-datetime-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Format the _datetime_ according to the string _format_.
| %y | Year in two digits |
| %Z | Time zone in time difference |
| %z | Abbreviation of Time zone name |
| %% | '%' |

> You can also use [the Time Layout of the Go Lang](https://golang.org/pkg/time/#Time.Format) as a format.
Expand Down
4 changes: 2 additions & 2 deletions docs/_posts/2006-01-02-flag.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ A flag is a representation of a [command option]({{ '/reference/command.html#glo
| @@DELIMITER | string | Field delimiter |
| @@ENCODING | string | File encoding |
| @@REPOSITORY | string | Directory path where files are located |
| @@NO-HEADER | boolean | Import first line as a record |
| @@WITHOUT-NULL | boolean | Parse empty field as empty string |
| @@NO_HEADER | boolean | Import first line as a record |
| @@WITHOUT_NULL | boolean | Parse empty field as empty string |


## Set Flag
Expand Down
14 changes: 7 additions & 7 deletions docs/_posts/2006-01-02-statement.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,23 @@ SELECT @id := @id + 1 AS id, -- Line Comment
{: #reserved_words}

ADD AFTER ALTER ALL AND ANY AS ASC
BEFORE BETWEEN BOOLEAN BREAK BY
BEFORE BETWEEN BREAK BY
CASE COMMIT CREATE CLOSE CONTINUE CROSS CURSOR
DATETIME DECLARE DEFAULT DELETE DESC DISPOSE DISTINCT DO DROP DUAL
DECLARE DEFAULT DELETE DESC DISPOSE DISTINCT DO DROP DUAL
ELSE ELSEIF END EXISTS EXIT
FETCH FIRST FLAG FLOAT FOR FROM FULL
FETCH FIRST FOR FROM FULL
GROUP GROUP_CONCAT
HAVING
IDENTIFIER IF IN INNER INSERT INTEGER INTO IS
IF IN INNER INSERT INTO IS
JOIN
LAST LEFT LIKE LIMIT
NATURAL NOT NULL
ON OPEN OR ORDER OUTER
PRINT
RENAME RIGHT ROLLBACK
SELECT SET SEPARATOR STDIN STRING
TABLE TERNARY THEN TO
SELECT SET SEPARATOR STDIN
TABLE THEN TO
UNION UPDATE USING
VALUES VAR VARIABLE
VALUES VAR
WHEN WHERE WHILE WITH

55 changes: 44 additions & 11 deletions lib/cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"bufio"
"io"
"strings"

"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
Expand All @@ -17,14 +16,48 @@ func GetReader(r io.Reader, enc Encoding) io.Reader {
}

func UnescapeString(s string) string {
s = strings.Replace(s, "\\a", "\a", -1)
s = strings.Replace(s, "\\b", "\b", -1)
s = strings.Replace(s, "\\f", "\f", -1)
s = strings.Replace(s, "\\n", "\n", -1)
s = strings.Replace(s, "\\r", "\r", -1)
s = strings.Replace(s, "\\t", "\t", -1)
s = strings.Replace(s, "\\v", "\v", -1)
s = strings.Replace(s, "\\\"", "\"", -1)
s = strings.Replace(s, "\\\\", "\\", -1)
return s
runes := []rune(s)
unescaped := []rune{}

escaped := false
for _, r := range runes {
if escaped {
switch r {
case 'a':
unescaped = append(unescaped, '\a')
case 'b':
unescaped = append(unescaped, '\b')
case 'f':
unescaped = append(unescaped, '\f')
case 'n':
unescaped = append(unescaped, '\n')
case 'r':
unescaped = append(unescaped, '\r')
case 't':
unescaped = append(unescaped, '\t')
case 'v':
unescaped = append(unescaped, '\v')
case '"':
unescaped = append(unescaped, '"')
case '\\':
unescaped = append(unescaped, '\\')
default:
unescaped = append(unescaped, '\\', r)
}
escaped = false
continue
}

if r == '\\' {
escaped = true
continue
}

unescaped = append(unescaped, r)
}
if escaped {
unescaped = append(unescaped, '\\')
}

return string(unescaped)
}
4 changes: 2 additions & 2 deletions lib/cmd/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func TestGetReader(t *testing.T) {
}

func TestUnescapeString(t *testing.T) {
str := "\\a\\b\\f\\n\\r\\t\\v\\\\\\\""
expect := "\a\b\f\n\r\t\v\\\""
str := "fo\\o\\a\\b\\f\\n\\r\\t\\v\\\\\\\"bar\\"
expect := "fo\\o\a\b\f\n\r\t\v\\\"bar\\"
unescaped := UnescapeString(str)
if unescaped != expect {
t.Errorf("unescaped string = %q, want %q", unescaped, expect)
Expand Down
6 changes: 6 additions & 0 deletions lib/parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,12 @@ func (f *Field) Name() string {
if f.Alias != nil {
return f.Alias.(Identifier).Literal
}
if s, ok := f.Object.(String); ok {
return s.Value()
}
if dt, ok := f.Object.(Datetime); ok {
return dt.literal
}
return f.Object.String()
}

Expand Down
16 changes: 16 additions & 0 deletions lib/parser/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,22 @@ func TestField_Name(t *testing.T) {
if e.Name() != expect {
t.Errorf("name = %q, want %q for %#v", e.Name(), expect, e)
}

e = Field{
Object: String{literal: "foo"},
}
expect = "foo"
if e.Name() != expect {
t.Errorf("name = %q, want %q for %#v", e.Name(), expect, e)
}

e = Field{
Object: NewDatetimeFromString("2012-01-01"),
}
expect = "2012-01-01"
if e.Name() != expect {
t.Errorf("name = %q, want %q for %#v", e.Name(), expect, e)
}
}

func TestAllColumns_String(t *testing.T) {
Expand Down
18 changes: 18 additions & 0 deletions lib/query/comparison.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,22 @@ func stringPattern(pattern []rune, position int) (int, int, string, int) {
search := []rune{}
returnPostion := position

escaped := false
for i := position; i < len(pattern); i++ {
r := pattern[i]

if escaped {
switch r {
case '%', '_':
search = append(search, r)
default:
search = append(search, '\\', r)
}
returnPostion++
escaped = false
continue
}

if (r == '%' || r == '_') && 0 < len(search) {
break
}
Expand All @@ -247,10 +260,15 @@ func stringPattern(pattern []rune, position int) (int, int, string, int) {
if -1 < anyRunesMaxLen {
anyRunesMaxLen++
}
case '\\':
escaped = true
default:
search = append(search, r)
}
}
if escaped {
search = append(search, '\\')
}

return anyRunesMinLen, anyRunesMaxLen, string(search), returnPostion
}
Expand Down
25 changes: 25 additions & 0 deletions lib/query/comparison_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,31 @@ var likeTests = []struct {
Pattern: parser.NewString("%def%_abc%"),
Result: ternary.TRUE,
},
{
LHS: parser.NewString("abcde"),
Pattern: parser.NewString("abc\\_e"),
Result: ternary.FALSE,
},
{
LHS: parser.NewString("abc_e"),
Pattern: parser.NewString("abc\\_e"),
Result: ternary.TRUE,
},
{
LHS: parser.NewString("abcde"),
Pattern: parser.NewString("abc\\%e"),
Result: ternary.FALSE,
},
{
LHS: parser.NewString("a\\bc%e"),
Pattern: parser.NewString("a\\bc\\%e"),
Result: ternary.TRUE,
},
{
LHS: parser.NewString("abcde\\"),
Pattern: parser.NewString("abcde\\"),
Result: ternary.TRUE,
},
}

func TestLike(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion lib/query/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func formatTextCell(c Cell) textField {
s = primary.(parser.Datetime).Format()
sign = -1
case parser.Null:
s = primary.String()
s = "NULL"
}

return textField{value: s, sign: sign}
Expand Down
6 changes: 3 additions & 3 deletions lib/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ func SetFlag(stmt parser.SetFlag) error {
switch strings.ToUpper(stmt.Name) {
case "@@DELIMITER", "@@ENCODING", "@@REPOSITORY":
p = parser.PrimaryToString(stmt.Value)
case "@@NO-HEADER", "@@WITHOUT-NULL":
case "@@NO_HEADER", "@@WITHOUT_NULL":
p = parser.PrimaryToBoolean(stmt.Value)
}
if parser.IsNull(p) {
Expand All @@ -889,9 +889,9 @@ func SetFlag(stmt parser.SetFlag) error {
err = cmd.SetEncoding(p.(parser.String).Value())
case "@@REPOSITORY":
err = cmd.SetRepository(p.(parser.String).Value())
case "@@NO-HEADER":
case "@@NO_HEADER":
err = cmd.SetNoHeader(p.(parser.Boolean).Bool())
case "@@WITHOUT-NULL":
case "@@WITHOUT_NULL":
err = cmd.SetWithoutNull(p.(parser.Boolean).Bool())
default:
err = errors.New(fmt.Sprintf("invalid flag name: %s", stmt.Name))
Expand Down
12 changes: 6 additions & 6 deletions lib/query/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2647,19 +2647,19 @@ var setFlagTests = []struct {
{
Name: "Set NoHeader",
Query: parser.SetFlag{
Name: "@@no-header",
Name: "@@no_header",
Value: parser.NewBoolean(true),
},
ResultFlag: "no-header",
ResultFlag: "no_header",
ResultBoolValue: true,
},
{
Name: "Set WithoutNull",
Query: parser.SetFlag{
Name: "@@without-null",
Name: "@@without_null",
Value: parser.NewBoolean(true),
},
ResultFlag: "without-null",
ResultFlag: "without_null",
ResultBoolValue: true,
},
{
Expand All @@ -2673,10 +2673,10 @@ var setFlagTests = []struct {
{
Name: "Set WithoutNull Value Error",
Query: parser.SetFlag{
Name: "@@without-null",
Name: "@@without_null",
Value: parser.NewString("string"),
},
Error: "invalid flag value: @@without-null = 'string'",
Error: "invalid flag value: @@without_null = 'string'",
},
{
Name: "Invalid Flag Error",
Expand Down

0 comments on commit fbf736d

Please sign in to comment.