join_multi_test.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. package plans
  2. import (
  3. "engine/xsql"
  4. "fmt"
  5. "reflect"
  6. "strings"
  7. "testing"
  8. )
  9. func TestMultiJoinPlan_Apply(t *testing.T) {
  10. var tests = []struct {
  11. sql string
  12. data xsql.WindowTuplesSet
  13. result interface{}
  14. }{
  15. {
  16. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 left join src3 on src2.id2 = src3.id3",
  17. data: xsql.WindowTuplesSet{
  18. xsql.WindowTuples{
  19. Emitter:"src1",
  20. Tuples:[]xsql.Tuple{
  21. {
  22. Emitter: "src1",
  23. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  24. },{
  25. Emitter: "src1",
  26. Message: xsql.Message{ "id1" : 3, "f1" : "v3" },
  27. },
  28. },
  29. },
  30. xsql.WindowTuples{
  31. Emitter:"src2",
  32. Tuples:[]xsql.Tuple{
  33. {
  34. Emitter: "src2",
  35. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  36. },{
  37. Emitter: "src2",
  38. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  39. },
  40. },
  41. },
  42. xsql.WindowTuples{
  43. Emitter:"src3",
  44. Tuples:[]xsql.Tuple{
  45. {
  46. Emitter: "src3",
  47. Message: xsql.Message{ "id3" : 1, "f3" : "x1" },
  48. },{
  49. Emitter: "src3",
  50. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  51. },
  52. },
  53. },
  54. },
  55. result: xsql.JoinTupleSets{
  56. xsql.JoinTuple{
  57. Tuples: []xsql.Tuple{
  58. {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  59. {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  60. {Emitter: "src3", Message: xsql.Message{ "id3" : 1, "f3" : "x1" },},
  61. },
  62. },
  63. xsql.JoinTuple{
  64. Tuples: []xsql.Tuple{
  65. {Emitter: "src1", Message: xsql.Message{ "id1" : 3, "f1" : "v3" },},
  66. },
  67. },
  68. },
  69. },
  70. {
  71. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 inner join src3 on src2.id2 = src3.id3",
  72. data: xsql.WindowTuplesSet{
  73. xsql.WindowTuples{
  74. Emitter:"src1",
  75. Tuples:[]xsql.Tuple{
  76. {
  77. Emitter: "src1",
  78. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  79. },{
  80. Emitter: "src1",
  81. Message: xsql.Message{ "id1" : 3, "f1" : "v3" },
  82. },
  83. },
  84. },
  85. xsql.WindowTuples{
  86. Emitter:"src2",
  87. Tuples:[]xsql.Tuple{
  88. {
  89. Emitter: "src2",
  90. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  91. },{
  92. Emitter: "src2",
  93. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  94. },
  95. },
  96. },
  97. xsql.WindowTuples{
  98. Emitter:"src3",
  99. Tuples:[]xsql.Tuple{
  100. {
  101. Emitter: "src3",
  102. Message: xsql.Message{ "id3" : 1, "f3" : "x1" },
  103. },{
  104. Emitter: "src3",
  105. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  106. },
  107. },
  108. },
  109. },
  110. result: xsql.JoinTupleSets{
  111. xsql.JoinTuple{
  112. Tuples: []xsql.Tuple{
  113. {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  114. {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  115. {Emitter: "src3", Message: xsql.Message{ "id3" : 1, "f3" : "x1" },},
  116. },
  117. },
  118. },
  119. },
  120. {
  121. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 inner join src3 on src1.id1 = src3.id3",
  122. data: xsql.WindowTuplesSet{
  123. xsql.WindowTuples{
  124. Emitter:"src1",
  125. Tuples:[]xsql.Tuple{
  126. {
  127. Emitter: "src1",
  128. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  129. },{
  130. Emitter: "src1",
  131. Message: xsql.Message{ "id1" : 5, "f1" : "v5" },
  132. },
  133. },
  134. },
  135. xsql.WindowTuples{
  136. Emitter:"src2",
  137. Tuples:[]xsql.Tuple{
  138. {
  139. Emitter: "src2",
  140. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  141. },{
  142. Emitter: "src2",
  143. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  144. },
  145. },
  146. },
  147. xsql.WindowTuples{
  148. Emitter:"src3",
  149. Tuples:[]xsql.Tuple{
  150. {
  151. Emitter: "src3",
  152. Message: xsql.Message{ "id3" : 2, "f3" : "x1" },
  153. },{
  154. Emitter: "src3",
  155. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  156. },
  157. },
  158. },
  159. },
  160. result: xsql.JoinTupleSets{
  161. xsql.JoinTuple{
  162. Tuples: []xsql.Tuple{
  163. {Emitter: "src1", Message: xsql.Message{ "id1" : 5, "f1" : "v5" },},
  164. {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  165. },
  166. },
  167. },
  168. },
  169. {
  170. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 full join src3 on src1.id1 = src3.id3",
  171. data: xsql.WindowTuplesSet{
  172. xsql.WindowTuples{
  173. Emitter:"src1",
  174. Tuples:[]xsql.Tuple{
  175. {
  176. Emitter: "src1",
  177. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  178. },{
  179. Emitter: "src1",
  180. Message: xsql.Message{ "id1" : 5, "f1" : "v5" },
  181. },
  182. },
  183. },
  184. xsql.WindowTuples{
  185. Emitter:"src2",
  186. Tuples:[]xsql.Tuple{
  187. {
  188. Emitter: "src2",
  189. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  190. },{
  191. Emitter: "src2",
  192. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  193. },
  194. },
  195. },
  196. xsql.WindowTuples{
  197. Emitter:"src3",
  198. Tuples:[]xsql.Tuple{
  199. {
  200. Emitter: "src3",
  201. Message: xsql.Message{ "id3" : 2, "f3" : "x1" },
  202. },{
  203. Emitter: "src3",
  204. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  205. },
  206. },
  207. },
  208. },
  209. result: xsql.JoinTupleSets{
  210. xsql.JoinTuple{
  211. Tuples: []xsql.Tuple{
  212. {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  213. {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  214. },
  215. },
  216. xsql.JoinTuple{
  217. Tuples: []xsql.Tuple{
  218. {Emitter: "src1", Message: xsql.Message{ "id1" : 5, "f1" : "v5" },},
  219. {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  220. },
  221. },
  222. xsql.JoinTuple{
  223. Tuples: []xsql.Tuple{
  224. {Emitter: "src3", Message: xsql.Message{ "id3" : 2, "f3" : "x1" },},
  225. },
  226. },
  227. },
  228. },
  229. {
  230. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 right join src3 on src2.id2 = src3.id3",
  231. data: xsql.WindowTuplesSet{
  232. xsql.WindowTuples{
  233. Emitter:"src1",
  234. Tuples:[]xsql.Tuple{
  235. {
  236. Emitter: "src1",
  237. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  238. },{
  239. Emitter: "src1",
  240. Message: xsql.Message{ "id1" : 3, "f1" : "v3" },
  241. },
  242. },
  243. },
  244. xsql.WindowTuples{
  245. Emitter:"src2",
  246. Tuples:[]xsql.Tuple{
  247. {
  248. Emitter: "src2",
  249. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  250. },{
  251. Emitter: "src2",
  252. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  253. },
  254. },
  255. },
  256. xsql.WindowTuples{
  257. Emitter:"src3",
  258. Tuples:[]xsql.Tuple{
  259. {
  260. Emitter: "src3",
  261. Message: xsql.Message{ "id3" : 1, "f3" : "x1" },
  262. },{
  263. Emitter: "src3",
  264. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  265. },
  266. },
  267. },
  268. },
  269. result: xsql.JoinTupleSets{
  270. xsql.JoinTuple{
  271. Tuples: []xsql.Tuple{
  272. {Emitter: "src3", Message: xsql.Message{ "id3" : 1, "f3" : "x1" },},
  273. {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  274. {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  275. },
  276. },
  277. xsql.JoinTuple{
  278. Tuples: []xsql.Tuple{
  279. {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  280. },
  281. },
  282. },
  283. },
  284. {
  285. sql: "SELECT id1 FROM src1 left join src2 on src1.id1 = src2.id2 cross join src3",
  286. data: xsql.WindowTuplesSet{
  287. xsql.WindowTuples{
  288. Emitter:"src1",
  289. Tuples:[]xsql.Tuple{
  290. {
  291. Emitter: "src1",
  292. Message: xsql.Message{ "id1" : 1, "f1" : "v1" },
  293. },{
  294. Emitter: "src1",
  295. Message: xsql.Message{ "id1" : 5, "f1" : "v5" },
  296. },
  297. },
  298. },
  299. xsql.WindowTuples{
  300. Emitter:"src2",
  301. Tuples:[]xsql.Tuple{
  302. {
  303. Emitter: "src2",
  304. Message: xsql.Message{ "id2" : 1, "f2" : "w1" },
  305. },{
  306. Emitter: "src2",
  307. Message: xsql.Message{ "id2" : 4, "f2" : "w3" },
  308. },
  309. },
  310. },
  311. xsql.WindowTuples{
  312. Emitter:"src3",
  313. Tuples:[]xsql.Tuple{
  314. {
  315. Emitter: "src3",
  316. Message: xsql.Message{ "id3" : 2, "f3" : "x1" },
  317. },{
  318. Emitter: "src3",
  319. Message: xsql.Message{ "id3" : 5, "f3" : "x5" },
  320. },
  321. },
  322. },
  323. },
  324. result: xsql.JoinTupleSets{
  325. xsql.JoinTuple{
  326. Tuples: []xsql.Tuple{
  327. {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  328. {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  329. {Emitter: "src3", Message: xsql.Message{ "id3" : 2, "f3" : "x1" },},
  330. {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  331. },
  332. },
  333. //xsql.JoinTuple{
  334. // Tuples: []xsql.Tuple{
  335. // {Emitter: "src1", Message: xsql.Message{ "id1" : 1, "f1" : "v1" },},
  336. // {Emitter: "src2", Message: xsql.Message{ "id2" : 1, "f2" : "w1" },},
  337. // {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  338. // },
  339. //},
  340. xsql.JoinTuple{
  341. Tuples: []xsql.Tuple{
  342. {Emitter: "src1", Message: xsql.Message{ "id1" : 5, "f1" : "v5" },},
  343. {Emitter: "src3", Message: xsql.Message{ "id3" : 2, "f3" : "x1" },},
  344. {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  345. },
  346. },
  347. //xsql.JoinTuple{
  348. // Tuples: []xsql.Tuple{
  349. // {Emitter: "src1", Message: xsql.Message{ "id1" : 5, "f1" : "v5" },},
  350. // {Emitter: "src3", Message: xsql.Message{ "id3" : 5, "f3" : "x5" },},
  351. // },
  352. //},
  353. },
  354. },
  355. }
  356. fmt.Printf("The test bucket size is %d.\n\n", len(tests))
  357. for i, tt := range tests {
  358. stmt, err := xsql.NewParser(strings.NewReader(tt.sql)).Parse()
  359. if err != nil {
  360. t.Errorf("statement parse error %s", err)
  361. break
  362. }
  363. if table, ok := stmt.Sources[0].(*xsql.Table); !ok{
  364. t.Errorf("statement source is not a table")
  365. }else{
  366. pp := &JoinPlan{Joins: stmt.Joins, From: table}
  367. result := pp.Apply(nil, tt.data)
  368. if !reflect.DeepEqual(tt.result, result) {
  369. t.Errorf("%d. %q\n\nresult mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.sql, tt.result, result)
  370. }
  371. }
  372. }
  373. }