1use mz_ore::assert_none;
13use mz_repr::{Datum, InputDatumType, OutputDatumType, ReprColumnType, RowArena, SqlColumnType};
14
15use crate::{Eval, EvalError};
16
17pub(crate) trait LazyBinaryFunc {
20 fn eval<'a>(
21 &'a self,
22 datums: &[Datum<'a>],
23 temp_storage: &'a RowArena,
24 exprs: &[&'a impl Eval],
25 ) -> Result<Datum<'a>, EvalError>;
26
27 fn output_sql_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType;
29
30 fn output_type(&self, input_types: &[ReprColumnType]) -> ReprColumnType {
32 ReprColumnType::from(
33 &self.output_sql_type(
34 &input_types
35 .iter()
36 .map(SqlColumnType::from_repr)
37 .collect::<Vec<_>>(),
38 ),
39 )
40 }
41
42 fn propagates_nulls(&self) -> bool;
44
45 fn introduces_nulls(&self) -> bool;
47
48 fn could_error(&self) -> bool {
50 true
52 }
53
54 fn negate(&self) -> Option<crate::BinaryFunc>;
56
57 fn is_monotone(&self) -> (bool, bool);
70
71 fn is_infinity_monotone(&self) -> bool {
80 true
81 }
82
83 fn is_infix_op(&self) -> bool;
85}
86
87pub(crate) trait EagerBinaryFunc {
88 type Input<'a>: InputDatumType<'a, EvalError>;
89 type Output<'a>: OutputDatumType<'a, EvalError>;
90
91 fn call<'a>(&self, input: Self::Input<'a>, temp_storage: &'a RowArena) -> Self::Output<'a>;
92
93 fn output_sql_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType;
95
96 #[allow(dead_code)]
98 fn output_type(&self, input_types: &[ReprColumnType]) -> ReprColumnType {
99 ReprColumnType::from(
100 &self.output_sql_type(
101 &input_types
102 .iter()
103 .map(SqlColumnType::from_repr)
104 .collect::<Vec<_>>(),
105 ),
106 )
107 }
108
109 fn propagates_nulls(&self) -> bool {
111 !Self::Input::nullable()
113 }
114
115 fn introduces_nulls(&self) -> bool {
117 Self::Output::nullable()
119 }
120
121 fn could_error(&self) -> bool {
123 Self::Output::fallible()
124 }
125
126 fn negate(&self) -> Option<crate::BinaryFunc> {
128 None
129 }
130
131 fn is_monotone(&self) -> (bool, bool) {
132 (false, false)
133 }
134
135 fn is_infinity_monotone(&self) -> bool {
136 true
137 }
138
139 fn is_infix_op(&self) -> bool {
140 false
141 }
142}
143
144impl<T: EagerBinaryFunc> LazyBinaryFunc for T {
145 fn eval<'a>(
146 &'a self,
147 datums: &[Datum<'a>],
148 temp_storage: &'a RowArena,
149 exprs: &[&'a impl Eval],
150 ) -> Result<Datum<'a>, EvalError> {
151 let mut datums = exprs
152 .into_iter()
153 .map(|expr| expr.eval(datums, temp_storage));
154 let input = match T::Input::try_from_iter(&mut datums) {
155 Ok(input) => input,
157 Err(Ok(Some(datum))) if !datum.is_null() => {
159 return Err(EvalError::Internal("invalid input type".into()));
160 }
161 Err(Ok(None)) => {
162 return Err(EvalError::Internal("unexpectedly missing parameter".into()));
163 }
164 Err(Ok(Some(datum))) => return Ok(datum),
166 Err(Err(res)) => return Err(res),
167 };
168 assert_none!(datums.next(), "No leftover input arguments");
169 self.call(input, temp_storage).into_result(temp_storage)
170 }
171
172 fn output_sql_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
173 self.output_sql_type(input_types)
174 }
175
176 fn propagates_nulls(&self) -> bool {
177 self.propagates_nulls()
178 }
179
180 fn introduces_nulls(&self) -> bool {
181 self.introduces_nulls()
182 }
183
184 fn could_error(&self) -> bool {
185 self.could_error()
186 }
187
188 fn negate(&self) -> Option<crate::BinaryFunc> {
189 self.negate()
190 }
191
192 fn is_monotone(&self) -> (bool, bool) {
193 self.is_monotone()
194 }
195
196 fn is_infinity_monotone(&self) -> bool {
197 self.is_infinity_monotone()
198 }
199
200 fn is_infix_op(&self) -> bool {
201 self.is_infix_op()
202 }
203}
204
205pub use derive::BinaryFunc;
206
207mod derive {
208 use std::fmt;
209
210 use mz_repr::{Datum, ReprColumnType, RowArena, SqlColumnType};
211
212 use crate::scalar::func::binary::LazyBinaryFunc;
213 use crate::scalar::func::*;
214 use crate::{Eval, EvalError};
215
216 derive_binary! {
217 AddInt16(AddInt16),
218 AddInt32(AddInt32),
219 AddInt64(AddInt64),
220 AddUint16(AddUint16),
221 AddUint32(AddUint32),
222 AddUint64(AddUint64),
223 AddFloat32(AddFloat32),
224 AddFloat64(AddFloat64),
225 AddInterval(AddInterval),
226 AddTimestampInterval(AddTimestampInterval),
227 AddTimestampTzInterval(AddTimestampTzInterval),
228 AddDateInterval(AddDateInterval),
229 AddDateTime(AddDateTime),
230 AddTimeInterval(AddTimeInterval),
231 AddNumeric(AddNumeric),
232 AgeTimestamp(AgeTimestamp),
233 AgeTimestampTz(AgeTimestampTz),
234 BitAndInt16(BitAndInt16),
235 BitAndInt32(BitAndInt32),
236 BitAndInt64(BitAndInt64),
237 BitAndUint16(BitAndUint16),
238 BitAndUint32(BitAndUint32),
239 BitAndUint64(BitAndUint64),
240 BitOrInt16(BitOrInt16),
241 BitOrInt32(BitOrInt32),
242 BitOrInt64(BitOrInt64),
243 BitOrUint16(BitOrUint16),
244 BitOrUint32(BitOrUint32),
245 BitOrUint64(BitOrUint64),
246 BitXorInt16(BitXorInt16),
247 BitXorInt32(BitXorInt32),
248 BitXorInt64(BitXorInt64),
249 BitXorUint16(BitXorUint16),
250 BitXorUint32(BitXorUint32),
251 BitXorUint64(BitXorUint64),
252 BitShiftLeftInt16(BitShiftLeftInt16),
253 BitShiftLeftInt32(BitShiftLeftInt32),
254 BitShiftLeftInt64(BitShiftLeftInt64),
255 BitShiftLeftUint16(BitShiftLeftUint16),
256 BitShiftLeftUint32(BitShiftLeftUint32),
257 BitShiftLeftUint64(BitShiftLeftUint64),
258 BitShiftRightInt16(BitShiftRightInt16),
259 BitShiftRightInt32(BitShiftRightInt32),
260 BitShiftRightInt64(BitShiftRightInt64),
261 BitShiftRightUint16(BitShiftRightUint16),
262 BitShiftRightUint32(BitShiftRightUint32),
263 BitShiftRightUint64(BitShiftRightUint64),
264 SubInt16(SubInt16),
265 SubInt32(SubInt32),
266 SubInt64(SubInt64),
267 SubUint16(SubUint16),
268 SubUint32(SubUint32),
269 SubUint64(SubUint64),
270 SubFloat32(SubFloat32),
271 SubFloat64(SubFloat64),
272 SubInterval(SubInterval),
273 SubTimestamp(SubTimestamp),
274 SubTimestampTz(SubTimestampTz),
275 SubTimestampInterval(SubTimestampInterval),
276 SubTimestampTzInterval(SubTimestampTzInterval),
277 SubDate(SubDate),
278 SubDateInterval(SubDateInterval),
279 SubTime(SubTime),
280 SubTimeInterval(SubTimeInterval),
281 SubNumeric(SubNumeric),
282 MulInt16(MulInt16),
283 MulInt32(MulInt32),
284 MulInt64(MulInt64),
285 MulUint16(MulUint16),
286 MulUint32(MulUint32),
287 MulUint64(MulUint64),
288 MulFloat32(MulFloat32),
289 MulFloat64(MulFloat64),
290 MulNumeric(MulNumeric),
291 MulInterval(MulInterval),
292 DivInt16(DivInt16),
293 DivInt32(DivInt32),
294 DivInt64(DivInt64),
295 DivUint16(DivUint16),
296 DivUint32(DivUint32),
297 DivUint64(DivUint64),
298 DivFloat32(DivFloat32),
299 DivFloat64(DivFloat64),
300 DivNumeric(DivNumeric),
301 DivInterval(DivInterval),
302 ModInt16(ModInt16),
303 ModInt32(ModInt32),
304 ModInt64(ModInt64),
305 ModUint16(ModUint16),
306 ModUint32(ModUint32),
307 ModUint64(ModUint64),
308 ModFloat32(ModFloat32),
309 ModFloat64(ModFloat64),
310 ModNumeric(ModNumeric),
311 RoundNumeric(RoundNumericBinary),
312 Eq(Eq),
313 NotEq(NotEq),
314 Lt(Lt),
315 Lte(Lte),
316 Gt(Gt),
317 Gte(Gte),
318 LikeEscape(LikeEscape),
319 IsLikeMatchCaseInsensitive(IsLikeMatchCaseInsensitive),
320 IsLikeMatchCaseSensitive(IsLikeMatchCaseSensitive),
321 IsRegexpMatchCaseSensitive(IsRegexpMatchCaseSensitive),
322 IsRegexpMatchCaseInsensitive(IsRegexpMatchCaseInsensitive),
323 ToCharTimestamp(ToCharTimestampFormat),
324 ToCharTimestampTz(ToCharTimestampTzFormat),
325 DateBinTimestamp(DateBinTimestamp),
326 DateBinTimestampTz(DateBinTimestampTz),
327 ExtractInterval(DatePartIntervalNumeric),
328 ExtractTime(DatePartTimeNumeric),
329 ExtractTimestamp(DatePartTimestampTimestampNumeric),
330 ExtractTimestampTz(DatePartTimestampTimestampTzNumeric),
331 ExtractDate(ExtractDateUnits),
332 DatePartInterval(DatePartIntervalF64),
333 DatePartTime(DatePartTimeF64),
334 DatePartTimestamp(DatePartTimestampTimestampF64),
335 DatePartTimestampTz(DatePartTimestampTimestampTzF64),
336 DateTruncTimestamp(DateTruncUnitsTimestamp),
337 DateTruncTimestampTz(DateTruncUnitsTimestampTz),
338 DateTruncInterval(DateTruncInterval),
339 TimezoneTimestampBinary(TimezoneTimestampBinary),
340 TimezoneTimestampTzBinary(TimezoneTimestampTzBinary),
341 TimezoneIntervalTimestampBinary(TimezoneIntervalTimestampBinary),
342 TimezoneIntervalTimestampTzBinary(TimezoneIntervalTimestampTzBinary),
343 TimezoneIntervalTimeBinary(TimezoneIntervalTimeBinary),
344 TimezoneOffset(TimezoneOffset),
345 TextConcat(TextConcatBinary),
346 JsonbGetInt64(JsonbGetInt64),
347 JsonbGetInt64Stringify(JsonbGetInt64Stringify),
348 JsonbGetString(JsonbGetString),
349 JsonbGetStringStringify(JsonbGetStringStringify),
350 JsonbGetPath(JsonbGetPath),
351 JsonbGetPathStringify(JsonbGetPathStringify),
352 JsonbContainsString(JsonbContainsString),
353 JsonbConcat(JsonbConcat),
354 JsonbContainsJsonb(JsonbContainsJsonb),
355 JsonbDeleteInt64(JsonbDeleteInt64),
356 JsonbDeleteString(JsonbDeleteString),
357 MapContainsKey(MapContainsKey),
358 MapGetValue(MapGetValue),
359 MapContainsAllKeys(MapContainsAllKeys),
360 MapContainsAnyKeys(MapContainsAnyKeys),
361 MapContainsMap(MapContainsMap),
362 ConvertFrom(ConvertFrom),
363 Left(Left),
364 Position(Position),
365 Strpos(Strpos),
366 Right(Right),
367 RepeatString(RepeatString),
368 Normalize(Normalize),
369 Trim(Trim),
370 TrimLeading(TrimLeading),
371 TrimTrailing(TrimTrailing),
372 EncodedBytesCharLength(EncodedBytesCharLength),
373 ListLengthMax(ListLengthMax),
374 ArrayContains(ArrayContains),
375 ArrayContainsArray(ArrayContainsArray),
376 ArrayContainsArrayRev(ArrayContainsArrayRev),
377 ArrayLength(ArrayLength),
378 ArrayLower(ArrayLower),
379 ArrayRemove(ArrayRemove),
380 ArrayUpper(ArrayUpper),
381 ArrayArrayConcat(ArrayArrayConcat),
382 ListListConcat(ListListConcat),
383 ListElementConcat(ListElementConcat),
384 ElementListConcat(ElementListConcat),
385 ListRemove(ListRemove),
386 ListContainsList(ListContainsList),
387 ListContainsListRev(ListContainsListRev),
388 DigestString(DigestString),
389 DigestBytes(DigestBytes),
390 MzRenderTypmod(MzRenderTypmod),
391 Encode(Encode),
392 Decode(Decode),
393 LogNumeric(LogBaseNumeric),
394 Power(Power),
395 PowerNumeric(PowerNumeric),
396 GetBit(GetBit),
397 GetByte(GetByte),
398 ConstantTimeEqBytes(ConstantTimeEqBytes),
399 ConstantTimeEqString(ConstantTimeEqString),
400 RangeContainsDate(RangeContainsDate),
401 RangeContainsDateRev(RangeContainsDateRev),
402 RangeContainsI32(RangeContainsI32),
403 RangeContainsI32Rev(RangeContainsI32Rev),
404 RangeContainsI64(RangeContainsI64),
405 RangeContainsI64Rev(RangeContainsI64Rev),
406 RangeContainsNumeric(RangeContainsNumeric),
407 RangeContainsNumericRev(RangeContainsNumericRev),
408 RangeContainsRange(RangeContainsRange),
409 RangeContainsRangeRev(RangeContainsRangeRev),
410 RangeContainsTimestamp(RangeContainsTimestamp),
411 RangeContainsTimestampRev(RangeContainsTimestampRev),
412 RangeContainsTimestampTz(RangeContainsTimestampTz),
413 RangeContainsTimestampTzRev(RangeContainsTimestampTzRev),
414 RangeOverlaps(RangeOverlaps),
415 RangeAfter(RangeAfter),
416 RangeBefore(RangeBefore),
417 RangeOverleft(RangeOverleft),
418 RangeOverright(RangeOverright),
419 RangeAdjacent(RangeAdjacent),
420 RangeUnion(RangeUnion),
421 RangeIntersection(RangeIntersection),
422 RangeDifference(RangeDifference),
423 UuidGenerateV5(UuidGenerateV5),
424 MzAclItemContainsPrivilege(MzAclItemContainsPrivilege),
425 ParseIdent(ParseIdent),
426 PrettySql(PrettySql),
427 RegexpReplace(RegexpReplace),
428 StartsWith(StartsWith),
429 }
430}
431
432#[cfg(test)]
433mod test {
434 use mz_expr_derive::sqlfunc;
435 use mz_repr::SqlScalarType;
436
437 use crate::EvalError;
438 use crate::scalar::func::binary::LazyBinaryFunc;
439
440 #[sqlfunc(sqlname = "INFALLIBLE", is_infix_op = true, test = true)]
441 #[allow(dead_code)]
442 fn infallible1(a: f32, b: f32) -> f32 {
443 a + b
444 }
445
446 #[sqlfunc(test = true)]
447 #[allow(dead_code)]
448 fn infallible2(a: Option<f32>, b: Option<f32>) -> f32 {
449 a.unwrap_or_default() + b.unwrap_or_default()
450 }
451
452 #[sqlfunc(test = true)]
453 #[allow(dead_code)]
454 fn infallible3(a: f32, b: f32) -> Option<f32> {
455 Some(a + b)
456 }
457
458 #[mz_ore::test]
459 fn elision_rules_infallible() {
460 assert_eq!(format!("{}", Infallible1), "INFALLIBLE");
461 assert!(Infallible1.propagates_nulls());
462 assert!(!Infallible1.introduces_nulls());
463
464 assert!(!Infallible2.propagates_nulls());
465 assert!(!Infallible2.introduces_nulls());
466
467 assert!(Infallible3.propagates_nulls());
468 assert!(Infallible3.introduces_nulls());
469 }
470
471 #[mz_ore::test]
472 fn output_types_infallible() {
473 assert_eq!(
474 Infallible1.output_sql_type(&[
475 SqlScalarType::Float32.nullable(true),
476 SqlScalarType::Float32.nullable(true)
477 ]),
478 SqlScalarType::Float32.nullable(true)
479 );
480 assert_eq!(
481 Infallible1.output_sql_type(&[
482 SqlScalarType::Float32.nullable(true),
483 SqlScalarType::Float32.nullable(false)
484 ]),
485 SqlScalarType::Float32.nullable(true)
486 );
487 assert_eq!(
488 Infallible1.output_sql_type(&[
489 SqlScalarType::Float32.nullable(false),
490 SqlScalarType::Float32.nullable(true)
491 ]),
492 SqlScalarType::Float32.nullable(true)
493 );
494 assert_eq!(
495 Infallible1.output_sql_type(&[
496 SqlScalarType::Float32.nullable(false),
497 SqlScalarType::Float32.nullable(false)
498 ]),
499 SqlScalarType::Float32.nullable(false)
500 );
501
502 assert_eq!(
503 Infallible2.output_sql_type(&[
504 SqlScalarType::Float32.nullable(true),
505 SqlScalarType::Float32.nullable(true)
506 ]),
507 SqlScalarType::Float32.nullable(false)
508 );
509 assert_eq!(
510 Infallible2.output_sql_type(&[
511 SqlScalarType::Float32.nullable(true),
512 SqlScalarType::Float32.nullable(false)
513 ]),
514 SqlScalarType::Float32.nullable(false)
515 );
516 assert_eq!(
517 Infallible2.output_sql_type(&[
518 SqlScalarType::Float32.nullable(false),
519 SqlScalarType::Float32.nullable(true)
520 ]),
521 SqlScalarType::Float32.nullable(false)
522 );
523 assert_eq!(
524 Infallible2.output_sql_type(&[
525 SqlScalarType::Float32.nullable(false),
526 SqlScalarType::Float32.nullable(false)
527 ]),
528 SqlScalarType::Float32.nullable(false)
529 );
530
531 assert_eq!(
532 Infallible3.output_sql_type(&[
533 SqlScalarType::Float32.nullable(true),
534 SqlScalarType::Float32.nullable(true)
535 ]),
536 SqlScalarType::Float32.nullable(true)
537 );
538 assert_eq!(
539 Infallible3.output_sql_type(&[
540 SqlScalarType::Float32.nullable(true),
541 SqlScalarType::Float32.nullable(false)
542 ]),
543 SqlScalarType::Float32.nullable(true)
544 );
545 assert_eq!(
546 Infallible3.output_sql_type(&[
547 SqlScalarType::Float32.nullable(false),
548 SqlScalarType::Float32.nullable(true)
549 ]),
550 SqlScalarType::Float32.nullable(true)
551 );
552 assert_eq!(
553 Infallible3.output_sql_type(&[
554 SqlScalarType::Float32.nullable(false),
555 SqlScalarType::Float32.nullable(false)
556 ]),
557 SqlScalarType::Float32.nullable(true)
558 );
559 }
560
561 #[sqlfunc(test = true)]
562 #[allow(dead_code)]
563 fn fallible1(a: f32, b: f32) -> Result<f32, EvalError> {
564 Ok(a + b)
565 }
566
567 #[sqlfunc(test = true)]
568 #[allow(dead_code)]
569 fn fallible2(a: Option<f32>, b: Option<f32>) -> Result<f32, EvalError> {
570 Ok(a.unwrap_or_default() + b.unwrap_or_default())
571 }
572
573 #[sqlfunc(test = true)]
574 #[allow(dead_code)]
575 fn fallible3(a: f32, b: f32) -> Result<Option<f32>, EvalError> {
576 Ok(Some(a + b))
577 }
578
579 #[mz_ore::test]
580 fn elision_rules_fallible() {
581 assert!(Fallible1.propagates_nulls());
582 assert!(!Fallible1.introduces_nulls());
583
584 assert!(!Fallible2.propagates_nulls());
585 assert!(!Fallible2.introduces_nulls());
586
587 assert!(Fallible3.propagates_nulls());
588 assert!(Fallible3.introduces_nulls());
589 }
590
591 #[mz_ore::test]
592 fn output_types_fallible() {
593 assert_eq!(
594 Fallible1.output_sql_type(&[
595 SqlScalarType::Float32.nullable(true),
596 SqlScalarType::Float32.nullable(true)
597 ]),
598 SqlScalarType::Float32.nullable(true)
599 );
600 assert_eq!(
601 Fallible1.output_sql_type(&[
602 SqlScalarType::Float32.nullable(true),
603 SqlScalarType::Float32.nullable(false)
604 ]),
605 SqlScalarType::Float32.nullable(true)
606 );
607 assert_eq!(
608 Fallible1.output_sql_type(&[
609 SqlScalarType::Float32.nullable(false),
610 SqlScalarType::Float32.nullable(true)
611 ]),
612 SqlScalarType::Float32.nullable(true)
613 );
614 assert_eq!(
615 Fallible1.output_sql_type(&[
616 SqlScalarType::Float32.nullable(false),
617 SqlScalarType::Float32.nullable(false)
618 ]),
619 SqlScalarType::Float32.nullable(false)
620 );
621
622 assert_eq!(
623 Fallible2.output_sql_type(&[
624 SqlScalarType::Float32.nullable(true),
625 SqlScalarType::Float32.nullable(true)
626 ]),
627 SqlScalarType::Float32.nullable(false)
628 );
629 assert_eq!(
630 Fallible2.output_sql_type(&[
631 SqlScalarType::Float32.nullable(true),
632 SqlScalarType::Float32.nullable(false)
633 ]),
634 SqlScalarType::Float32.nullable(false)
635 );
636 assert_eq!(
637 Fallible2.output_sql_type(&[
638 SqlScalarType::Float32.nullable(false),
639 SqlScalarType::Float32.nullable(true)
640 ]),
641 SqlScalarType::Float32.nullable(false)
642 );
643 assert_eq!(
644 Fallible2.output_sql_type(&[
645 SqlScalarType::Float32.nullable(false),
646 SqlScalarType::Float32.nullable(false)
647 ]),
648 SqlScalarType::Float32.nullable(false)
649 );
650
651 assert_eq!(
652 Fallible3.output_sql_type(&[
653 SqlScalarType::Float32.nullable(true),
654 SqlScalarType::Float32.nullable(true)
655 ]),
656 SqlScalarType::Float32.nullable(true)
657 );
658 assert_eq!(
659 Fallible3.output_sql_type(&[
660 SqlScalarType::Float32.nullable(true),
661 SqlScalarType::Float32.nullable(false)
662 ]),
663 SqlScalarType::Float32.nullable(true)
664 );
665 assert_eq!(
666 Fallible3.output_sql_type(&[
667 SqlScalarType::Float32.nullable(false),
668 SqlScalarType::Float32.nullable(true)
669 ]),
670 SqlScalarType::Float32.nullable(true)
671 );
672 assert_eq!(
673 Fallible3.output_sql_type(&[
674 SqlScalarType::Float32.nullable(false),
675 SqlScalarType::Float32.nullable(false)
676 ]),
677 SqlScalarType::Float32.nullable(true)
678 );
679 }
680
681 #[mz_ore::test]
682 fn mz_reflect_binary_func() {
683 use crate::BinaryFunc;
684 use mz_lowertest::{MzReflect, ReflectedTypeInfo};
685
686 let mut rti = ReflectedTypeInfo::default();
687 BinaryFunc::add_to_reflected_type_info(&mut rti);
688
689 let variants = rti
691 .enum_dict
692 .get("BinaryFunc")
693 .expect("BinaryFunc should be in enum_dict");
694 assert!(
695 variants.contains_key("AddInt64"),
696 "AddInt64 variant should exist"
697 );
698 assert!(variants.contains_key("Gte"), "Gte variant should exist");
699
700 assert!(
702 rti.struct_dict.contains_key("AddInt64"),
703 "AddInt64 should be in struct_dict"
704 );
705 assert!(
706 rti.struct_dict.contains_key("Gte"),
707 "Gte should be in struct_dict"
708 );
709
710 let (names, types) = rti.struct_dict.get("AddInt64").unwrap();
712 assert!(names.is_empty(), "AddInt64 should have no field names");
713 assert!(types.is_empty(), "AddInt64 should have no field types");
714 }
715}