funcs_validator_test.go 14 KB

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