funcsAstValidator_test.go 14 KB

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