funcs_validator_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // Copyright 2022 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package xsql
  15. import (
  16. "fmt"
  17. "github.com/lf-edge/ekuiper/internal/testx"
  18. "github.com/lf-edge/ekuiper/pkg/ast"
  19. "reflect"
  20. "strings"
  21. "testing"
  22. )
  23. // Ensure the parser can parse strings into Statement ASTs.
  24. func TestFuncValidator(t *testing.T) {
  25. var tests = []struct {
  26. s string
  27. stmt *ast.SelectStatement
  28. err string
  29. }{
  30. {
  31. s: `SELECT abs(1) FROM tbl`,
  32. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "abs", Expr: &ast.Call{Name: "abs", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}}}}},
  33. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  34. },
  35. },
  36. {
  37. s: `SELECT abs(field1) FROM tbl`,
  38. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "abs", Expr: &ast.Call{Name: "abs", Args: []ast.Expr{&ast.FieldRef{Name: "field1", StreamName: ast.DefaultStream}}}}},
  39. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  40. },
  41. },
  42. {
  43. s: `SELECT abs(1,2) FROM tbl`,
  44. stmt: nil,
  45. err: "Expect 1 arguments but found 2.",
  46. },
  47. {
  48. s: `SELECT abs(1.1) FROM tbl`,
  49. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "abs", Expr: &ast.Call{Name: "abs", Args: []ast.Expr{&ast.NumberLiteral{Val: 1.1}}}}},
  50. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  51. },
  52. },
  53. {
  54. s: `SELECT abs(true) FROM tbl`,
  55. stmt: nil,
  56. err: "Expect number - float or int type for parameter 1",
  57. },
  58. {
  59. s: `SELECT abs("test") FROM tbl`,
  60. stmt: nil,
  61. err: "Expect number - float or int type for parameter 1",
  62. },
  63. {
  64. s: `SELECT abs(ss) FROM tbl`,
  65. stmt: nil,
  66. err: "Expect number - float or int type for parameter 1",
  67. },
  68. ///
  69. {
  70. s: `SELECT sin(1) FROM tbl`,
  71. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "sin", Expr: &ast.Call{Name: "sin", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}}}}},
  72. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  73. },
  74. },
  75. {
  76. s: `SELECT sin(1.1) FROM tbl`,
  77. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "sin", Expr: &ast.Call{Name: "sin", Args: []ast.Expr{&ast.NumberLiteral{Val: 1.1}}}}},
  78. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  79. },
  80. },
  81. {
  82. s: `SELECT sin(true) FROM tbl`,
  83. stmt: nil,
  84. err: "Expect number - float or int type for parameter 1",
  85. },
  86. {
  87. s: `SELECT sin("test") FROM tbl`,
  88. stmt: nil,
  89. err: "Expect number - float or int type for parameter 1",
  90. },
  91. {
  92. s: `SELECT sin(ss) FROM tbl`,
  93. stmt: nil,
  94. err: "Expect number - float or int type for parameter 1",
  95. },
  96. ///
  97. {
  98. s: `SELECT tanh(1) FROM tbl`,
  99. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "tanh", Expr: &ast.Call{Name: "tanh", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}}}}},
  100. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  101. },
  102. },
  103. {
  104. s: `SELECT tanh(1.1) FROM tbl`,
  105. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "tanh", Expr: &ast.Call{Name: "tanh", Args: []ast.Expr{&ast.NumberLiteral{Val: 1.1}}}}},
  106. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  107. },
  108. },
  109. {
  110. s: `SELECT tanh(true) FROM tbl`,
  111. stmt: nil,
  112. err: "Expect number - float or int type for parameter 1",
  113. },
  114. {
  115. s: `SELECT tanh("test") FROM tbl`,
  116. stmt: nil,
  117. err: "Expect number - float or int type for parameter 1",
  118. },
  119. {
  120. s: `SELECT tanh(ss) FROM tbl`,
  121. stmt: nil,
  122. err: "Expect number - float or int type for parameter 1",
  123. },
  124. ///
  125. {
  126. s: `SELECT bitxor(1, 2) FROM tbl`,
  127. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "bitxor", Expr: &ast.Call{Name: "bitxor", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}, &ast.IntegerLiteral{Val: 2}}}}},
  128. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  129. },
  130. },
  131. {
  132. s: `SELECT bitxor(1.1, 2) FROM tbl`,
  133. stmt: nil,
  134. err: "Expect int type for parameter 1",
  135. },
  136. {
  137. s: `SELECT bitxor(true, 2) FROM tbl`,
  138. stmt: nil,
  139. err: "Expect int type for parameter 1",
  140. },
  141. {
  142. s: `SELECT bitxor(1, ss) FROM tbl`,
  143. stmt: nil,
  144. err: "Expect int type for parameter 2",
  145. },
  146. {
  147. s: `SELECT bitxor(1, 2.2) FROM tbl`,
  148. stmt: nil,
  149. err: "Expect int type for parameter 2",
  150. },
  151. ///
  152. {
  153. s: `SELECT bitnot(1) FROM tbl`,
  154. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "bitnot", Expr: &ast.Call{Name: "bitnot", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}}}}},
  155. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  156. },
  157. },
  158. {
  159. s: `SELECT bitnot(1.1) FROM tbl`,
  160. stmt: nil,
  161. err: "Expect int type for parameter 1",
  162. },
  163. {
  164. s: `SELECT bitnot(true) FROM tbl`,
  165. stmt: nil,
  166. err: "Expect int type for parameter 1",
  167. },
  168. ///
  169. {
  170. s: `SELECT mod(1, 2) FROM tbl`,
  171. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "mod", Expr: &ast.Call{Name: "mod", Args: []ast.Expr{&ast.IntegerLiteral{Val: 1}, &ast.IntegerLiteral{Val: 2}}}}},
  172. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  173. },
  174. },
  175. {
  176. s: `SELECT mod("1.1", 2) FROM tbl`,
  177. stmt: nil,
  178. err: "Expect number - float or int type for parameter 1",
  179. },
  180. {
  181. s: `SELECT mod(1.1, true) FROM tbl`,
  182. stmt: nil,
  183. err: "Expect number - float or int type for parameter 2",
  184. },
  185. {
  186. s: `SELECT mod(1, ss) FROM tbl`,
  187. stmt: nil,
  188. err: "Expect number - float or int type for parameter 2",
  189. },
  190. ///
  191. {
  192. s: `SELECT concat(field, "hello") FROM tbl`,
  193. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "concat", Expr: &ast.Call{Name: "concat", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.StringLiteral{Val: "hello"}}}}},
  194. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  195. },
  196. },
  197. {
  198. s: `SELECT concat("1.1", 2) FROM tbl`,
  199. stmt: nil,
  200. err: "Expect string type for parameter 2",
  201. },
  202. {
  203. s: `SELECT concat("1.1", true) FROM tbl`,
  204. stmt: nil,
  205. err: "Expect string type for parameter 2",
  206. },
  207. {
  208. s: `SELECT concat("1", ss) FROM tbl`,
  209. stmt: nil,
  210. err: "Expect string type for parameter 2",
  211. },
  212. ///
  213. {
  214. s: `SELECT regexp_matches(field, "hello") FROM tbl`,
  215. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "regexp_matches", Expr: &ast.Call{Name: "regexp_matches", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.StringLiteral{Val: "hello"}}}}},
  216. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  217. },
  218. },
  219. {
  220. s: `SELECT regexp_matches(1, "true") FROM tbl`,
  221. stmt: nil,
  222. err: "Expect string type for parameter 1",
  223. },
  224. {
  225. s: `SELECT regexp_matches("1.1", 2) FROM tbl`,
  226. stmt: nil,
  227. err: "Expect string type for parameter 2",
  228. },
  229. ///
  230. {
  231. s: `SELECT regexp_replace(field, "hello", "h") FROM tbl`,
  232. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "regexp_replace", Expr: &ast.Call{Name: "regexp_replace", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.StringLiteral{Val: "hello"}, &ast.StringLiteral{Val: "h"}}}}},
  233. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  234. },
  235. },
  236. {
  237. s: `SELECT regexp_replace(field1, "true", true) FROM tbl`,
  238. stmt: nil,
  239. err: "Expect string type for parameter 3",
  240. },
  241. ///
  242. {
  243. s: `SELECT trim(field) FROM tbl`,
  244. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "trim", Expr: &ast.Call{Name: "trim", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}}}}},
  245. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  246. },
  247. },
  248. {
  249. s: `SELECT trim(1) FROM tbl`,
  250. stmt: nil,
  251. err: "Expect string type for parameter 1",
  252. },
  253. ///
  254. {
  255. s: `SELECT rpad(field, 3) FROM tbl`,
  256. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "rpad", Expr: &ast.Call{Name: "rpad", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.IntegerLiteral{Val: 3}}}}},
  257. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  258. },
  259. },
  260. {
  261. s: `SELECT rpad("ff", true) FROM tbl`,
  262. stmt: nil,
  263. err: "Expect int type for parameter 2",
  264. },
  265. ///
  266. {
  267. s: `SELECT substring(field, 3, 4) FROM tbl`,
  268. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "substring", Expr: &ast.Call{Name: "substring", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.IntegerLiteral{Val: 3}, &ast.IntegerLiteral{Val: 4}}}}},
  269. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  270. },
  271. },
  272. {
  273. s: `SELECT substring(field, -1, 4) FROM tbl`,
  274. stmt: nil,
  275. err: "The start index should not be a nagtive integer.",
  276. },
  277. {
  278. s: `SELECT substring(field, 0, -1) FROM tbl`,
  279. stmt: nil,
  280. err: "The end index should be larger than start index.",
  281. },
  282. {
  283. s: `SELECT substring(field, 0, true) FROM tbl`,
  284. stmt: nil,
  285. err: "Expect int type for parameter 3",
  286. },
  287. ///
  288. {
  289. s: `SELECT cast(field, "bigint") FROM tbl`,
  290. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "cast", Expr: &ast.Call{Name: "cast", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.StringLiteral{Val: "bigint"}}}}},
  291. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  292. },
  293. },
  294. {
  295. s: `SELECT cast("12", "bool") FROM tbl`,
  296. stmt: nil,
  297. err: "Expect one of following value for the 2nd parameter: bigint, float, string, boolean, datetime.",
  298. },
  299. ///
  300. {
  301. s: `SELECT chr(field) FROM tbl`,
  302. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "chr", Expr: &ast.Call{Name: "chr", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}}}}},
  303. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  304. },
  305. },
  306. {
  307. s: `SELECT chr(true) FROM tbl`,
  308. stmt: nil,
  309. err: "Expect int type for parameter 1",
  310. },
  311. ///
  312. {
  313. s: `SELECT encode(field, "base64") FROM tbl`,
  314. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "encode", Expr: &ast.Call{Name: "encode", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.StringLiteral{Val: "base64"}}}}},
  315. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  316. },
  317. },
  318. {
  319. s: `SELECT encode(field, true) FROM tbl`,
  320. stmt: nil,
  321. err: "Expect string type for parameter 2",
  322. },
  323. ///
  324. {
  325. s: `SELECT trunc(field, 3) FROM tbl`,
  326. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "trunc", Expr: &ast.Call{Name: "trunc", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}, &ast.IntegerLiteral{Val: 3}}}}},
  327. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  328. },
  329. },
  330. {
  331. s: `SELECT trunc(5, ss) FROM tbl`,
  332. stmt: nil,
  333. err: "Expect int type for parameter 2",
  334. },
  335. ///
  336. {
  337. s: `SELECT sha512(field) FROM tbl`,
  338. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "sha512", Expr: &ast.Call{Name: "sha512", Args: []ast.Expr{&ast.FieldRef{Name: "field", StreamName: ast.DefaultStream}}}}},
  339. Sources: []ast.Source{&ast.Table{Name: "tbl"}},
  340. },
  341. },
  342. {
  343. s: `SELECT sha512(20) FROM tbl`,
  344. stmt: nil,
  345. err: "Expect string type for parameter 1",
  346. },
  347. {
  348. s: `SELECT mqtt("topic") FROM tbl`,
  349. stmt: nil,
  350. err: "Expect meta reference type for parameter 1",
  351. },
  352. {
  353. s: `SELECT mqtt(topic1) FROM tbl`,
  354. stmt: nil,
  355. err: "Parameter of mqtt function can be only topic or messageid.",
  356. },
  357. {
  358. s: `SELECT split_value(topic1) FROM tbl`,
  359. stmt: nil,
  360. err: "the arguments for split_value should be 3",
  361. },
  362. {
  363. s: `SELECT split_value(topic1, 3, 1) FROM tbl`,
  364. stmt: nil,
  365. err: "Expect string type for parameter 2",
  366. },
  367. {
  368. s: `SELECT split_value(topic1, "hello", -1) FROM tbl`,
  369. stmt: nil,
  370. err: "The index should not be a nagtive integer.",
  371. },
  372. {
  373. s: `SELECT meta(tbl, "timestamp", 1) FROM tbl`,
  374. stmt: nil,
  375. err: "Expect 1 arguments but found 3.",
  376. },
  377. {
  378. s: `SELECT meta("src1.device") FROM tbl`,
  379. stmt: nil,
  380. err: "Expect meta reference type for parameter 1",
  381. },
  382. {
  383. s: `SELECT meta(device) FROM tbl`,
  384. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "meta", Expr: &ast.Call{Name: "meta", Args: []ast.Expr{&ast.MetaRef{Name: "device", StreamName: ast.DefaultStream}}}}}, Sources: []ast.Source{&ast.Table{Name: "tbl"}}},
  385. },
  386. {
  387. s: `SELECT meta(tbl.device) FROM tbl`,
  388. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "meta", Expr: &ast.Call{Name: "meta", Args: []ast.Expr{&ast.MetaRef{StreamName: "tbl", Name: "device"}}}}}, Sources: []ast.Source{&ast.Table{Name: "tbl"}}},
  389. },
  390. {
  391. s: `SELECT meta(device->reading->topic) FROM tbl`,
  392. stmt: &ast.SelectStatement{Fields: []ast.Field{{AName: "", Name: "meta", Expr: &ast.Call{Name: "meta", Args: []ast.Expr{&ast.BinaryExpr{
  393. OP: ast.ARROW,
  394. LHS: &ast.BinaryExpr{
  395. OP: ast.ARROW,
  396. LHS: &ast.MetaRef{Name: "device", StreamName: ast.DefaultStream},
  397. RHS: &ast.JsonFieldRef{Name: "reading"},
  398. },
  399. RHS: &ast.JsonFieldRef{Name: "topic"},
  400. }}}}}, Sources: []ast.Source{&ast.Table{Name: "tbl"}}},
  401. },
  402. {
  403. s: `SELECT json_path_query(data, 44) AS data
  404. FROM characters;`,
  405. stmt: nil,
  406. err: "Expect string type for parameter 2",
  407. },
  408. {
  409. s: `SELECT collect() from tbl`,
  410. stmt: nil,
  411. err: "Expect 1 arguments but found 0.",
  412. },
  413. {
  414. s: `SELECT deduplicate(abc, temp, true) from tbl`,
  415. stmt: nil,
  416. err: "Expect 2 arguments but found 3.",
  417. },
  418. {
  419. s: `SELECT deduplicate(temp, "string") from tbl`,
  420. stmt: nil,
  421. err: "Expect bool type for parameter 2",
  422. },
  423. }
  424. fmt.Printf("The test bucket size is %d.\n\n", len(tests))
  425. for i, tt := range tests {
  426. //fmt.Printf("Parsing SQL %q.\n", tt.s)
  427. stmt, err := NewParser(strings.NewReader(tt.s)).Parse()
  428. if !reflect.DeepEqual(tt.err, testx.Errstring(err)) {
  429. t.Errorf("%d. %q: error mismatch:\n exp=%s\n got=%s\n\n", i, tt.s, tt.err, err)
  430. } else if tt.err == "" && !reflect.DeepEqual(tt.stmt, stmt) {
  431. t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt)
  432. }
  433. }
  434. }