@@ -140,3 +140,85 @@ async fn union_schemas() -> Result<()> {
140140 assert_batches_eq ! ( expected, & result) ;
141141 Ok ( ( ) )
142142}
143+
144+ #[ tokio:: test]
145+ async fn union_with_except_input ( ) -> Result < ( ) > {
146+ let ctx = create_union_context ( ) ?;
147+ let sql = "(
148+ SELECT name FROM t1
149+ EXCEPT
150+ SELECT name FROM t2
151+ )
152+ UNION ALL
153+ (
154+ SELECT name FROM t2
155+ EXCEPT
156+ SELECT name FROM t1
157+ )" ;
158+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
159+ let dataframe = ctx. sql ( & ( "explain " . to_owned ( ) + sql) ) . await . expect ( & msg) ;
160+ let plan = dataframe. into_optimized_plan ( ) ?;
161+ let expected = vec ! [
162+ "Explain [plan_type:Utf8, plan:Utf8]" ,
163+ " Union [name:UInt8;N]" ,
164+ " LeftAnti Join: t1.name = t2.name [name:UInt8;N]" ,
165+ " Distinct: [name:UInt8;N]" ,
166+ " TableScan: t1 projection=[name] [name:UInt8;N]" ,
167+ " Projection: t2.name [name:UInt8;N]" ,
168+ " TableScan: t2 projection=[name] [name:UInt8;N]" ,
169+ " LeftAnti Join: t2.name = t1.name [name:UInt8;N]" ,
170+ " Distinct: [name:UInt8;N]" ,
171+ " TableScan: t2 projection=[name] [name:UInt8;N]" ,
172+ " Projection: t1.name [name:UInt8;N]" ,
173+ " TableScan: t1 projection=[name] [name:UInt8;N]" ,
174+ ] ;
175+
176+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
177+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
178+ assert_eq ! (
179+ expected, actual,
180+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
181+ ) ;
182+ Ok ( ( ) )
183+ }
184+
185+ #[ tokio:: test]
186+ async fn union_with_type_coercion ( ) -> Result < ( ) > {
187+ let ctx = create_union_context ( ) ?;
188+ let sql = "(
189+ SELECT id, name FROM t1
190+ EXCEPT
191+ SELECT id, name FROM t2
192+ )
193+ UNION ALL
194+ (
195+ SELECT id, name FROM t2
196+ EXCEPT
197+ SELECT id, name FROM t1
198+ )" ;
199+ let msg = format ! ( "Creating logical plan for '{sql}'" ) ;
200+ let dataframe = ctx. sql ( & ( "explain " . to_owned ( ) + sql) ) . await . expect ( & msg) ;
201+ let plan = dataframe. into_optimized_plan ( ) ?;
202+ let expected = vec ! [
203+ "Explain [plan_type:Utf8, plan:Utf8]" ,
204+ " Union [id:Int32;N, name:UInt8;N]" ,
205+ " LeftAnti Join: t1.id = CAST(t2.id AS Int32), t1.name = t2.name [id:Int32;N, name:UInt8;N]" ,
206+ " Distinct: [id:Int32;N, name:UInt8;N]" ,
207+ " TableScan: t1 projection=[id, name] [id:Int32;N, name:UInt8;N]" ,
208+ " Projection: t2.id, t2.name [id:UInt8;N, name:UInt8;N]" ,
209+ " TableScan: t2 projection=[id, name] [id:UInt8;N, name:UInt8;N]" ,
210+ " Projection: CAST(t2.id AS Int32) AS id, t2.name [id:Int32;N, name:UInt8;N]" ,
211+ " LeftAnti Join: CAST(t2.id AS Int32) = t1.id, t2.name = t1.name [id:UInt8;N, name:UInt8;N]" ,
212+ " Distinct: [id:UInt8;N, name:UInt8;N]" ,
213+ " TableScan: t2 projection=[id, name] [id:UInt8;N, name:UInt8;N]" ,
214+ " Projection: t1.id, t1.name [id:Int32;N, name:UInt8;N]" ,
215+ " TableScan: t1 projection=[id, name] [id:Int32;N, name:UInt8;N]" ,
216+ ] ;
217+ let formatted = plan. display_indent_schema ( ) . to_string ( ) ;
218+ let actual: Vec < & str > = formatted. trim ( ) . lines ( ) . collect ( ) ;
219+ assert_eq ! (
220+ expected, actual,
221+ "\n \n expected:\n \n {expected:#?}\n actual:\n \n {actual:#?}\n \n "
222+ ) ;
223+ Ok ( ( ) )
224+ }
0 commit comments