From 5bd8c3c850aaf5878bd0ee9421d54ab1dfacdf6f Mon Sep 17 00:00:00 2001 From: Marc Egerton Date: Tue, 11 Feb 2020 19:27:08 +0000 Subject: [PATCH] sql: Add support for ON CONFLICT REPLACE --- sql/Makefile | 3 + sql/parser.go | 564 +++++++++++++++++++++++++---------------------- sql/parser.go.y | 49 ++-- sql/sql_test.go | 17 ++ sql/tokenizer.go | 2 + 5 files changed, 362 insertions(+), 273 deletions(-) diff --git a/sql/Makefile b/sql/Makefile index 8a19976..b1b8cf8 100644 --- a/sql/Makefile +++ b/sql/Makefile @@ -10,3 +10,6 @@ test: parser.go build: parser.go go build + +get: + go get golang.org/x/tools/cmd/goyacc diff --git a/sql/parser.go b/sql/parser.go index 11d50d8..ca7e762 100644 --- a/sql/parser.go +++ b/sql/parser.go @@ -39,63 +39,71 @@ type yySymType struct { float float64 } -const ACTION = 57346 -const AND = 57347 -const ASC = 57348 -const AUTOINCREMENT = 57349 -const CASCADE = 57350 -const COLLATE = 57351 -const CONSTRAINT = 57352 -const CREATE = 57353 -const DEFAULT = 57354 -const DEFERRABLE = 57355 -const DEFERRED = 57356 -const DELETE = 57357 -const DESC = 57358 -const FOREIGN = 57359 -const FROM = 57360 -const GLOB = 57361 -const IN = 57362 -const INDEX = 57363 -const INITIALLY = 57364 -const IS = 57365 -const KEY = 57366 -const LIKE = 57367 -const MATCH = 57368 -const NO = 57369 -const NOT = 57370 -const NULL = 57371 -const ON = 57372 -const OR = 57373 -const PRIMARY = 57374 -const REFERENCES = 57375 -const REGEXP = 57376 -const RESTRICT = 57377 -const ROWID = 57378 -const SELECT = 57379 -const SET = 57380 -const TABLE = 57381 -const UNIQUE = 57382 -const UPDATE = 57383 -const WHERE = 57384 -const WITHOUT = 57385 -const tBare = 57386 -const tLiteral = 57387 -const tIdentifier = 57388 -const tOperator = 57389 -const tSignedNumber = 57390 -const tFloat = 57391 +const ABORT = 57346 +const ACTION = 57347 +const AND = 57348 +const ASC = 57349 +const AUTOINCREMENT = 57350 +const CASCADE = 57351 +const COLLATE = 57352 +const CONFLICT = 57353 +const CONSTRAINT = 57354 +const CREATE = 57355 +const DEFAULT = 57356 +const DEFERRABLE = 57357 +const DEFERRED = 57358 +const DELETE = 57359 +const DESC = 57360 +const FAIL = 57361 +const FOREIGN = 57362 +const FROM = 57363 +const GLOB = 57364 +const IGNORE = 57365 +const IN = 57366 +const INDEX = 57367 +const INITIALLY = 57368 +const IS = 57369 +const KEY = 57370 +const LIKE = 57371 +const MATCH = 57372 +const NO = 57373 +const NOT = 57374 +const NULL = 57375 +const ON = 57376 +const OR = 57377 +const PRIMARY = 57378 +const REFERENCES = 57379 +const REGEXP = 57380 +const REPLACE = 57381 +const RESTRICT = 57382 +const ROLLBACK = 57383 +const ROWID = 57384 +const SELECT = 57385 +const SET = 57386 +const TABLE = 57387 +const UNIQUE = 57388 +const UPDATE = 57389 +const WHERE = 57390 +const WITHOUT = 57391 +const tBare = 57392 +const tLiteral = 57393 +const tIdentifier = 57394 +const tOperator = 57395 +const tSignedNumber = 57396 +const tFloat = 57397 var yyToknames = [...]string{ "$end", "error", "$unk", + "ABORT", "ACTION", "AND", "ASC", "AUTOINCREMENT", "CASCADE", "COLLATE", + "CONFLICT", "CONSTRAINT", "CREATE", "DEFAULT", @@ -103,9 +111,11 @@ var yyToknames = [...]string{ "DEFERRED", "DELETE", "DESC", + "FAIL", "FOREIGN", "FROM", "GLOB", + "IGNORE", "IN", "INDEX", "INITIALLY", @@ -121,7 +131,9 @@ var yyToknames = [...]string{ "PRIMARY", "REFERENCES", "REGEXP", + "REPLACE", "RESTRICT", + "ROLLBACK", "ROWID", "SELECT", "SET", @@ -154,65 +166,66 @@ var yyExca = [...]int{ 1, -1, -2, 0, -1, 77, - 53, 6, - -2, 81, + 59, 6, + -2, 87, -1, 78, - 53, 7, - -2, 82, + 59, 7, + -2, 88, } const yyPrivate = 57344 -const yyLast = 187 +const yyLast = 195 var yyAct = [...]int{ - 73, 152, 9, 125, 88, 71, 10, 68, 74, 127, - 139, 61, 75, 132, 18, 145, 69, 10, 21, 132, - 23, 133, 72, 26, 95, 48, 131, 31, 32, 26, - 130, 95, 129, 124, 108, 106, 52, 77, 76, 78, - 102, 62, 82, 80, 81, 59, 79, 84, 95, 99, - 96, 47, 101, 100, 60, 67, 122, 94, 28, 93, - 65, 66, 46, 36, 62, 37, 63, 64, 62, 82, - 80, 81, 91, 92, 99, 22, 55, 101, 100, 86, - 62, 17, 63, 64, 11, 103, 12, 35, 114, 91, - 92, 150, 107, 104, 105, 65, 66, 13, 15, 154, - 39, 51, 115, 111, 6, 117, 118, 119, 121, 10, - 116, 126, 112, 33, 123, 16, 49, 151, 156, 87, - 128, 11, 136, 12, 50, 44, 155, 149, 45, 153, - 5, 27, 159, 10, 58, 135, 134, 137, 25, 56, - 10, 85, 126, 142, 43, 42, 83, 57, 40, 158, - 53, 144, 19, 157, 89, 8, 41, 147, 141, 35, - 98, 110, 160, 143, 90, 140, 120, 34, 70, 113, - 146, 148, 20, 29, 38, 109, 97, 54, 14, 30, - 24, 7, 138, 4, 3, 2, 1, + 73, 160, 9, 125, 88, 71, 10, 68, 74, 127, + 147, 61, 75, 134, 18, 153, 69, 10, 21, 134, + 23, 135, 95, 26, 131, 72, 108, 31, 32, 26, + 99, 106, 102, 101, 100, 84, 52, 122, 130, 95, + 129, 124, 77, 76, 78, 59, 62, 82, 80, 81, + 62, 79, 63, 64, 60, 67, 95, 94, 96, 93, + 65, 66, 47, 36, 62, 37, 63, 64, 62, 82, + 80, 81, 91, 92, 99, 46, 22, 101, 100, 17, + 28, 35, 65, 66, 48, 103, 11, 55, 12, 91, + 92, 114, 107, 104, 105, 158, 13, 15, 87, 139, + 6, 157, 115, 111, 33, 117, 118, 119, 121, 10, + 116, 126, 112, 51, 123, 39, 16, 133, 27, 11, + 128, 12, 58, 44, 85, 159, 25, 45, 141, 49, + 5, 162, 83, 167, 57, 10, 136, 138, 86, 50, + 145, 53, 152, 142, 155, 43, 42, 143, 10, 40, + 126, 150, 166, 164, 56, 34, 19, 89, 8, 41, + 149, 165, 163, 144, 35, 140, 161, 137, 90, 98, + 110, 168, 132, 151, 148, 20, 120, 70, 113, 154, + 156, 29, 38, 109, 97, 54, 14, 30, 24, 7, + 146, 4, 3, 2, 1, } var yyPact = [...]int{ - 93, -1000, -1000, -1000, -1000, 40, 58, 63, -1000, -1000, - -1000, -1000, -1000, 40, 131, -1000, 40, 40, 22, 40, - -1000, -1000, 40, 101, 6, -1000, 40, 40, 77, 11, - 116, 9, -2, 84, -1000, 40, 149, 33, 116, -1000, - 123, -1000, -1000, 105, 40, 16, 32, -7, -1000, 122, - -6, 117, -1000, 84, -1000, 83, -1000, 148, -1000, -1000, - -1000, -1000, -1000, 32, 32, -1000, -1000, 5, -4, -1000, - 151, 27, -1000, -13, -1000, -1000, -1000, -1000, -1000, -7, - 20, 20, -1000, -18, -7, -19, -1000, -1000, 154, -1000, - -1000, -1000, -1000, -1000, 32, -7, 46, 148, 51, -7, - -7, -7, -7, 2, -1000, -1000, -7, -21, 40, -1000, - -1000, -45, -1000, -1000, -7, -1000, -1000, 27, 27, 27, - -22, 27, -1000, -28, -1000, -33, -1000, -1000, 27, -1000, - -7, -1000, 40, 89, 27, -1000, 40, -43, 145, 40, - 129, -1000, -39, -1000, 143, -1000, 97, -1000, -1000, 76, - 91, 91, -1000, 120, -1000, -1000, 158, -1000, -1000, -1000, - -1000, + 87, -1000, -1000, -1000, -1000, 36, 51, 58, -1000, -1000, + -1000, -1000, -1000, 36, 131, -1000, 36, 36, 17, 36, + -1000, -1000, 36, 84, 22, -1000, 36, 36, 69, 5, + 113, 16, 3, 93, -1000, 36, 152, 38, 113, -1000, + 106, -1000, -1000, 89, 36, 10, -4, -8, -1000, 104, + -24, 96, -1000, 93, -1000, 56, -1000, 150, -1000, -1000, + -1000, -1000, -1000, -4, -4, -1000, -1000, -1, -2, -1000, + 159, 21, -1000, -27, -1000, -1000, -1000, -1000, -1000, -8, + 14, 14, -1000, -28, -8, -33, -1000, -1000, 162, -1000, + -1000, -1000, -1000, -1000, -4, -8, 43, 150, 32, -8, + -8, -8, -8, -23, -1000, -1000, -8, -19, 36, -1000, + -1000, -51, -1000, -1000, -8, -1000, -1000, 21, 21, 21, + -20, 21, -1000, -36, 83, -39, -1000, -1000, 21, -1000, + -8, -1000, -1000, 156, 36, 62, 21, 124, -1000, 36, + -1000, -1000, -1000, -1000, -1000, -49, 145, 36, 116, -1000, + -45, -1000, 128, -1000, 67, -1000, -1000, 78, 122, 122, + -1000, 119, -1000, -1000, 166, -1000, -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 186, 185, 184, 183, 0, 11, 8, 12, 2, - 155, 3, 182, 181, 180, 138, 7, 16, 179, 113, - 178, 177, 176, 4, 175, 100, 174, 25, 173, 1, - 171, 170, 169, 168, 5, 166, 165, 163, + 0, 194, 193, 192, 191, 0, 11, 8, 12, 2, + 158, 3, 190, 189, 188, 126, 7, 16, 187, 104, + 186, 185, 184, 4, 183, 115, 182, 84, 181, 1, + 180, 179, 178, 177, 5, 176, 174, 173, 172, } var yyR1 = [...]int{ @@ -221,64 +234,64 @@ var yyR1 = [...]int{ 13, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 27, 27, 27, 19, 19, 28, 28, 28, 24, 24, 14, 14, 15, 18, 18, 18, 18, 22, 22, - 23, 23, 23, 21, 21, 20, 20, 16, 16, 33, - 17, 29, 29, 29, 29, 29, 30, 30, 31, 31, - 36, 36, 37, 37, 32, 32, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, - 2, 3, 4, + 23, 23, 23, 21, 21, 20, 20, 38, 38, 38, + 38, 38, 38, 16, 16, 33, 17, 29, 29, 29, + 29, 29, 30, 30, 31, 31, 36, 36, 37, 37, + 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 35, 35, 35, 2, 3, 4, } var yyR2 = [...]int{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 3, 3, 1, 1, 3, 4, 1, 1, 2, 2, 2, 2, 0, 1, - 2, 5, 4, 11, 0, 2, 0, 3, 4, 0, + 2, 5, 5, 11, 0, 2, 0, 3, 4, 0, 1, 1, 3, 3, 0, 1, 4, 6, 0, 2, - 0, 1, 1, 0, 2, 0, 1, 1, 3, 1, - 3, 2, 2, 1, 1, 2, 3, 3, 0, 2, - 0, 1, 0, 2, 0, 2, 1, 4, 1, 1, - 1, 1, 1, 3, 3, 3, 3, 0, 1, 3, - 4, 8, 10, + 0, 1, 1, 0, 2, 0, 1, 0, 3, 3, + 3, 3, 3, 1, 3, 1, 3, 2, 2, 1, + 1, 2, 3, 3, 0, 2, 0, 1, 0, 2, + 0, 2, 1, 4, 1, 1, 1, 1, 1, 3, + 3, 3, 3, 0, 1, 3, 4, 8, 10, } var yyChk = [...]int{ - -1000, -1, -2, -3, -4, 37, 11, -13, -10, -9, - -5, 44, 46, 39, -20, 40, 52, 18, -5, 21, - -10, -5, 53, -5, -14, -15, -5, 30, 52, -28, - -18, -5, -5, -19, -15, 10, 52, 54, -26, -25, - 32, 40, 29, 28, 9, 12, 53, 53, -27, 32, - 40, 17, -5, -19, -21, 43, -25, 24, 29, -5, - -7, -6, 48, 50, 51, 44, 45, -7, -16, -17, - -33, -34, 29, -5, -7, -8, 45, 44, 46, 53, - 50, 51, 49, 24, 53, 24, -27, 36, -23, 6, - 16, -7, -7, 54, 52, 52, 54, -22, 9, 47, - 51, 50, 53, -34, -8, -8, 53, -16, 53, -24, - 7, -7, -17, -32, 42, -23, -6, -34, -34, -34, - -35, -34, 54, -16, 54, -11, -9, 54, -34, 54, - 52, 54, 52, 54, -34, -9, 33, -5, -12, 53, - -36, 13, -11, -37, 22, 54, -31, 14, -30, 30, - 15, 41, -29, 38, 8, 35, 27, -29, 29, 12, - 4, + -1000, -1, -2, -3, -4, 43, 13, -13, -10, -9, + -5, 50, 52, 45, -20, 46, 58, 21, -5, 25, + -10, -5, 59, -5, -14, -15, -5, 34, 58, -28, + -18, -5, -5, -19, -15, 12, 58, 60, -26, -25, + 36, 46, 33, 32, 10, 14, 59, 59, -27, 36, + 46, 20, -5, -19, -21, 49, -25, 28, 33, -5, + -7, -6, 54, 56, 57, 50, 51, -7, -16, -17, + -33, -34, 33, -5, -7, -8, 51, 50, 52, 59, + 56, 57, 55, 28, 59, 28, -27, 42, -23, 7, + 18, -7, -7, 60, 58, 58, 60, -22, 10, 53, + 57, 56, 59, -34, -8, -8, 59, -16, 59, -24, + 8, -7, -17, -32, 48, -23, -6, -34, -34, -34, + -35, -34, 60, -16, 60, -11, -9, 60, -34, 60, + 58, 60, -38, 34, 58, 60, -34, 11, -9, 37, + 41, 4, 19, 23, 39, -5, -12, 59, -36, 15, + -11, -37, 26, 60, -31, 16, -30, 34, 17, 47, + -29, 44, 9, 40, 31, -29, 33, 14, 5, } var yyDef = [...]int{ 0, -2, 1, 2, 3, 0, 55, 0, 19, 18, 14, 6, 7, 0, 0, 56, 0, 0, 0, 0, - 20, 90, 0, 0, 36, 41, 44, 0, 34, 0, + 20, 96, 0, 0, 36, 41, 44, 0, 34, 0, 28, 45, 0, 0, 42, 0, 34, 53, 43, 29, 0, 22, 23, 0, 0, 0, 0, 0, 37, 0, - 0, 0, 35, 0, 91, 0, 30, 50, 24, 25, - 26, 27, 8, 0, 0, 4, 5, 0, 0, 57, - 48, 59, 76, 0, 78, 79, 80, -2, -2, 0, + 0, 0, 35, 0, 97, 0, 30, 50, 24, 25, + 26, 27, 8, 0, 0, 4, 5, 0, 0, 63, + 48, 65, 82, 0, 84, 85, 86, -2, -2, 0, 0, 0, 11, 0, 0, 0, 38, 54, 39, 51, - 52, 9, 10, 46, 0, 0, 74, 50, 0, 0, - 0, 0, 87, 0, 12, 13, 0, 0, 0, 21, - 40, 0, 58, 92, 0, 60, 49, 83, 84, 85, - 0, 88, 86, 0, 32, 0, 15, 47, 75, 77, - 0, 31, 0, 0, 89, 16, 0, 0, 70, 0, - 72, 71, 0, 68, 0, 17, 33, 73, 69, 0, - 0, 0, 66, 0, 63, 64, 0, 67, 61, 62, - 65, + 52, 9, 10, 46, 0, 0, 80, 50, 0, 0, + 0, 0, 93, 0, 12, 13, 0, 0, 0, 21, + 40, 0, 64, 98, 0, 66, 49, 89, 90, 91, + 0, 94, 92, 0, 57, 0, 15, 47, 81, 83, + 0, 31, 32, 0, 0, 0, 95, 0, 16, 0, + 58, 59, 60, 61, 62, 0, 76, 0, 78, 77, + 0, 74, 0, 17, 33, 79, 75, 0, 0, 0, + 72, 0, 69, 70, 0, 73, 67, 68, 71, } var yyTok1 = [...]int{ @@ -286,7 +299,7 @@ var yyTok1 = [...]int{ 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, - 53, 54, 3, 51, 52, 50, + 59, 60, 3, 57, 58, 56, } var yyTok2 = [...]int{ @@ -294,7 +307,8 @@ var yyTok2 = [...]int{ 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, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, } var yyTok3 = [...]int{ 0, @@ -639,181 +653,183 @@ yydefault: case 4: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:122 +//line parser.go.y:128 { yyVAL.literal = yyDollar[1].identifier } case 5: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:125 +//line parser.go.y:131 { yyVAL.literal = yyDollar[1].identifier } case 6: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:130 +//line parser.go.y:136 { yyVAL.identifier = yyDollar[1].identifier } case 7: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:133 +//line parser.go.y:139 { yyVAL.identifier = yyDollar[1].identifier } case 8: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:138 +//line parser.go.y:144 { yyVAL.signedNumber = yyDollar[1].signedNumber } case 9: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:141 +//line parser.go.y:147 { yyVAL.signedNumber = -yyDollar[2].signedNumber } case 10: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:144 +//line parser.go.y:150 { yyVAL.signedNumber = yyDollar[2].signedNumber } case 11: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:149 +//line parser.go.y:155 { yyVAL.float = yyDollar[1].float } case 12: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:152 +//line parser.go.y:158 { yyVAL.float = -yyDollar[2].float } case 13: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:155 +//line parser.go.y:161 { yyVAL.float = yyDollar[2].float } case 14: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:160 +//line parser.go.y:166 { yyVAL.columnName = yyDollar[1].identifier } case 15: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:165 +//line parser.go.y:171 { yyVAL.columnNameList = []string{yyDollar[1].columnName} } case 16: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:168 +//line parser.go.y:174 { yyVAL.columnNameList = append(yyDollar[1].columnNameList, yyDollar[3].columnName) } case 17: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:173 +//line parser.go.y:179 { yyVAL.columnNameList = yyDollar[2].columnNameList } case 18: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:178 +//line parser.go.y:184 { yyVAL.columnName = yyDollar[1].columnName } case 19: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:183 +//line parser.go.y:189 { yyVAL.columnNameList = []string{yyDollar[1].columnName} } case 20: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:186 +//line parser.go.y:192 { yyVAL.columnNameList = append(yyDollar[1].columnNameList, yyDollar[3].columnName) } case 21: yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:192 +//line parser.go.y:198 { yyVAL.columnConstraint = ccPrimaryKey{yyDollar[3].sortOrder, yyDollar[4].bool} } case 22: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:195 +//line parser.go.y:201 { yyVAL.columnConstraint = ccUnique(true) } case 23: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:198 +//line parser.go.y:204 { yyVAL.columnConstraint = ccNull(true) } case 24: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:201 +//line parser.go.y:207 { yyVAL.columnConstraint = ccNull(false) } case 25: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:204 +//line parser.go.y:210 { yyVAL.columnConstraint = ccCollate(yyDollar[2].identifier) } case 26: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:207 +//line parser.go.y:213 { yyVAL.columnConstraint = ccDefault(yyDollar[2].signedNumber) } case 27: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:210 +//line parser.go.y:216 { yyVAL.columnConstraint = ccDefault(yyDollar[2].literal) } case 28: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:215 +//line parser.go.y:221 { yyVAL.columnConstraintList = nil } case 29: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:218 +//line parser.go.y:224 { yyVAL.columnConstraintList = []columnConstraint{yyDollar[1].columnConstraint} } case 30: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:221 +//line parser.go.y:227 { yyVAL.columnConstraintList = append(yyDollar[1].columnConstraintList, yyDollar[2].columnConstraint) } case 31: yyDollar = yyS[yypt-5 : yypt+1] -//line parser.go.y:226 +//line parser.go.y:232 { yyVAL.tableConstraint = TablePrimaryKey{yyDollar[4].indexedColumnList} } case 32: - yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:229 + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:235 { - yyVAL.tableConstraint = TableUnique{yyDollar[3].indexedColumnList} + yyVAL.tableConstraint = TableUnique{ + IndexedColumns: yyDollar[3].indexedColumnList, + } } case 33: yyDollar = yyS[yypt-11 : yypt+1] -//line parser.go.y:232 +//line parser.go.y:240 { yyVAL.tableConstraint = TableForeignKey{ Columns: yyDollar[4].columnNameList, @@ -826,342 +842,372 @@ yydefault: } case 34: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:244 +//line parser.go.y:252 { } case 35: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:245 +//line parser.go.y:253 { } case 36: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:249 +//line parser.go.y:257 { } case 37: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:250 +//line parser.go.y:258 { yyVAL.tableConstraintList = []TableConstraint{yyDollar[3].tableConstraint} } case 38: yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:253 +//line parser.go.y:261 { yyVAL.tableConstraintList = append(yyDollar[1].tableConstraintList, yyDollar[4].tableConstraint) } case 39: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:259 +//line parser.go.y:267 { } case 40: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:260 +//line parser.go.y:268 { yyVAL.bool = true } case 41: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:265 +//line parser.go.y:273 { yyVAL.columnDefList = []ColumnDef{yyDollar[1].columnDef} } case 42: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:268 +//line parser.go.y:276 { yyVAL.columnDefList = append(yyDollar[1].columnDefList, yyDollar[3].columnDef) } case 43: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:273 +//line parser.go.y:281 { yyVAL.columnDef = makeColumnDef(yyDollar[1].identifier, yyDollar[2].name, yyDollar[3].columnConstraintList) } case 44: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:278 +//line parser.go.y:286 { yyVAL.name = "" } case 45: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:281 +//line parser.go.y:289 { yyVAL.name = yyDollar[1].identifier } case 46: yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:284 +//line parser.go.y:292 { yyVAL.name = yyDollar[1].identifier } case 47: yyDollar = yyS[yypt-6 : yypt+1] -//line parser.go.y:287 +//line parser.go.y:295 { yyVAL.name = yyDollar[1].identifier } case 48: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:292 +//line parser.go.y:300 { } case 49: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:293 +//line parser.go.y:301 { yyVAL.collate = yyDollar[2].literal } case 50: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:298 +//line parser.go.y:306 { yyVAL.sortOrder = Asc } case 51: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:301 +//line parser.go.y:309 { yyVAL.sortOrder = Asc } case 52: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:304 +//line parser.go.y:312 { yyVAL.sortOrder = Desc } case 53: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:309 +//line parser.go.y:317 { yyVAL.withoutRowid = false } case 54: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:312 +//line parser.go.y:320 { yyVAL.withoutRowid = true } case 55: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:317 +//line parser.go.y:325 { yyVAL.unique = false } case 56: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:320 +//line parser.go.y:328 { yyVAL.unique = true } case 57: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:333 + { + } + case 58: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:334 + { + } + case 59: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:336 + { + } + case 60: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:338 + { + } + case 61: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:340 + { + } + case 62: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:342 + { + } + case 63: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:325 +//line parser.go.y:346 { yyVAL.indexedColumnList = []IndexedColumn{yyDollar[1].indexedColumn} } - case 58: + case 64: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:328 +//line parser.go.y:349 { yyVAL.indexedColumnList = append(yyDollar[1].indexedColumnList, yyDollar[3].indexedColumn) } - case 59: + case 65: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:333 +//line parser.go.y:354 { yyVAL.expr = yyDollar[1].expr } - case 60: + case 66: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:338 +//line parser.go.y:359 { yyVAL.indexedColumn = newIndexColumn(yyDollar[1].expr, yyDollar[2].collate, yyDollar[3].sortOrder) } - case 61: + case 67: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:343 +//line parser.go.y:364 { yyVAL.triggerAction = ActionSetNull } - case 62: + case 68: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:346 +//line parser.go.y:367 { yyVAL.triggerAction = ActionSetDefault } - case 63: + case 69: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:349 +//line parser.go.y:370 { yyVAL.triggerAction = ActionCascade } - case 64: + case 70: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:352 +//line parser.go.y:373 { yyVAL.triggerAction = ActionRestrict } - case 65: + case 71: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:355 +//line parser.go.y:376 { yyVAL.triggerAction = ActionNoAction } - case 66: + case 72: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:360 +//line parser.go.y:381 { yyVAL.trigger = TriggerOnDelete(yyDollar[3].triggerAction) } - case 67: + case 73: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:363 +//line parser.go.y:384 { yyVAL.trigger = TriggerOnUpdate(yyDollar[3].triggerAction) } - case 68: + case 74: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:368 +//line parser.go.y:389 { } - case 69: + case 75: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:369 +//line parser.go.y:390 { yyVAL.triggerList = append(yyDollar[1].triggerList, yyDollar[2].trigger) } - case 70: + case 76: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:374 +//line parser.go.y:395 { yyVAL.bool = false } - case 71: + case 77: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:377 +//line parser.go.y:398 { yyVAL.bool = true } - case 72: + case 78: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:382 +//line parser.go.y:403 { yyVAL.bool = false } - case 73: + case 79: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:384 +//line parser.go.y:406 { yyVAL.bool = true } - case 74: + case 80: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:389 +//line parser.go.y:411 { } - case 75: + case 81: yyDollar = yyS[yypt-2 : yypt+1] -//line parser.go.y:390 +//line parser.go.y:412 { yyVAL.where = yyDollar[2].expr } - case 76: + case 82: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:395 +//line parser.go.y:417 { yyVAL.expr = nil } - case 77: + case 83: yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:398 +//line parser.go.y:420 { yyVAL.expr = ExFunction{yyDollar[1].identifier, yyDollar[3].exprList} } - case 78: + case 84: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:401 +//line parser.go.y:423 { yyVAL.expr = yyDollar[1].signedNumber } - case 79: + case 85: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:404 +//line parser.go.y:426 { yyVAL.expr = yyDollar[1].float } - case 80: + case 86: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:407 +//line parser.go.y:429 { yyVAL.expr = yyDollar[1].identifier } - case 81: + case 87: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:410 +//line parser.go.y:432 { yyVAL.expr = ExColumn(yyDollar[1].identifier) } - case 82: + case 88: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:413 +//line parser.go.y:435 { yyVAL.expr = ExColumn(yyDollar[1].identifier) } - case 83: + case 89: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:416 +//line parser.go.y:438 { yyVAL.expr = ExBinaryOp{yyDollar[2].identifier, yyDollar[1].expr, yyDollar[3].expr} } - case 84: + case 90: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:419 +//line parser.go.y:441 { yyVAL.expr = ExBinaryOp{"+", yyDollar[1].expr, yyDollar[3].expr} } - case 85: + case 91: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:422 +//line parser.go.y:444 { yyVAL.expr = ExBinaryOp{"-", yyDollar[1].expr, yyDollar[3].expr} } - case 86: + case 92: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:425 +//line parser.go.y:447 { yyVAL.expr = yyDollar[2].expr } - case 87: + case 93: yyDollar = yyS[yypt-0 : yypt+1] -//line parser.go.y:430 +//line parser.go.y:452 { yyVAL.exprList = nil } - case 88: + case 94: yyDollar = yyS[yypt-1 : yypt+1] -//line parser.go.y:433 +//line parser.go.y:455 { yyVAL.exprList = []Expression{yyDollar[1].expr} } - case 89: + case 95: yyDollar = yyS[yypt-3 : yypt+1] -//line parser.go.y:436 +//line parser.go.y:458 { yyVAL.exprList = append(yyDollar[1].exprList, yyDollar[3].expr) } - case 90: + case 96: yyDollar = yyS[yypt-4 : yypt+1] -//line parser.go.y:441 +//line parser.go.y:463 { yylex.(*lexer).result = SelectStmt{Columns: yyDollar[2].columnNameList, Table: yyDollar[4].identifier} } - case 91: + case 97: yyDollar = yyS[yypt-8 : yypt+1] -//line parser.go.y:446 +//line parser.go.y:468 { yylex.(*lexer).result = CreateTableStmt{ Table: yyDollar[3].identifier, @@ -1170,9 +1216,9 @@ yydefault: WithoutRowid: yyDollar[8].withoutRowid, } } - case 92: + case 98: yyDollar = yyS[yypt-10 : yypt+1] -//line parser.go.y:456 +//line parser.go.y:478 { yylex.(*lexer).result = CreateIndexStmt{ Index: yyDollar[4].identifier, diff --git a/sql/parser.go.y b/sql/parser.go.y index 34eeefd..317e168 100644 --- a/sql/parser.go.y +++ b/sql/parser.go.y @@ -66,12 +66,14 @@ package sql %type deferrable %type initiallyDeferred +%token ABORT %token ACTION %token AND %token ASC %token AUTOINCREMENT %token CASCADE %token COLLATE +%token CONFLICT %token CONSTRAINT %token CREATE %token DEFAULT @@ -79,9 +81,11 @@ package sql %token DEFERRED %token DELETE %token DESC +%token FAIL %token FOREIGN %token FROM %token GLOB +%token IGNORE %token IN %token INDEX %token INITIALLY @@ -97,7 +101,9 @@ package sql %token PRIMARY %token REFERENCES %token REGEXP +%token REPLACE %token RESTRICT +%token ROLLBACK %token ROWID %token SELECT %token SET @@ -226,8 +232,10 @@ tableConstraint: PRIMARY KEY '(' indexedColumnList ')' { $$ = TablePrimaryKey{$4} } | - UNIQUE '(' indexedColumnList ')' { - $$ = TableUnique{$3} + UNIQUE '(' indexedColumnList ')' onConflict { + $$ = TableUnique{ + IndexedColumns: $3, + } } | FOREIGN KEY '(' columnNameList ')' REFERENCES identifier optColumnNameList deferrable initiallyDeferred triggerList { $$ = TableForeignKey{ @@ -321,6 +329,19 @@ unique: $$ = true } +onConflict: + { } | + ON CONFLICT ROLLBACK { + } | + ON CONFLICT ABORT { + } | + ON CONFLICT FAIL { + } | + ON CONFLICT IGNORE { + } | + ON CONFLICT REPLACE { + } + indexedColumnList: indexedColumn { $$ = []IndexedColumn{$1} @@ -371,20 +392,20 @@ triggerList: } deferrable: - { - $$ = false - } | - DEFERRABLE { - $$ = true - } + { + $$ = false + } | + DEFERRABLE { + $$ = true + } initiallyDeferred: - { - $$ = false - } | - INITIALLY DEFERRED { - $$ = true - } + { + $$ = false + } | + INITIALLY DEFERRED { + $$ = true + } where: { } | diff --git a/sql/sql_test.go b/sql/sql_test.go index 85d98db..3b74775 100644 --- a/sql/sql_test.go +++ b/sql/sql_test.go @@ -240,6 +240,23 @@ func TestCreateTable(t *testing.T) { }, ) + sqlOK(t, + "CREATE TABLE table1 ( data INT, UNIQUE (data) ON CONFLICT REPLACE )", + CreateTableStmt{ + Table: "table1", + Columns: []ColumnDef{ + {Name: "data", Null: true, Type: "INT"}, + }, + Constraints: []TableConstraint{ + TableUnique{ + IndexedColumns: []IndexedColumn{ + {Column: "data", SortOrder: Asc}, + }, + }, + }, + }, + ) + // CREATE TABLE column definition tests. // a nil value means we expect an error cases := map[string]*ColumnDef{ diff --git a/sql/tokenizer.go b/sql/tokenizer.go index 5a9a813..200809f 100644 --- a/sql/tokenizer.go +++ b/sql/tokenizer.go @@ -17,6 +17,7 @@ var ( "AUTOINCREMENT": AUTOINCREMENT, "CASCADE": CASCADE, "COLLATE": COLLATE, + "CONFLICT": CONFLICT, "CONSTRAINT": CONSTRAINT, "CREATE": CREATE, "DEFAULT": DEFAULT, @@ -39,6 +40,7 @@ var ( "PRIMARY": PRIMARY, "REFERENCES": REFERENCES, "REGEXP": REGEXP, + "REPLACE": REPLACE, "RESTRICT": RESTRICT, "ROWID": ROWID, "SELECT": SELECT,