Skip to main content

drizzle_types/sql/
coerce.rs

1use super::DataType;
2
3#[diagnostic::on_unimplemented(
4    message = "SQL type `{Self}` is not compatible with `{Rhs}`",
5    label = "these SQL types cannot be compared or coerced",
6    note = "compatible types include: integers with integers/floats, text with text/varchar, and any type with itself"
7)]
8pub trait Compatible<Rhs: DataType = Self>: DataType {}
9
10#[diagnostic::on_unimplemented(
11    message = "SQL type `{Self}` is not assignable from `{Rhs}`",
12    label = "this value type cannot be bound to the placeholder/column type",
13    note = "assignment is stricter than comparison compatibility; use a value matching the target SQL marker"
14)]
15pub trait Assignable<Rhs: DataType = Self>: DataType {}
16
17// =============================================================================
18// Core macros
19// =============================================================================
20
21macro_rules! impl_reflexive_compat {
22    ($($ty:ty),+ $(,)?) => {
23        $(impl Compatible<$ty> for $ty {})+
24    };
25}
26
27macro_rules! impl_reflexive_assign {
28    ($($ty:ty),+ $(,)?) => {
29        $(impl Assignable<$ty> for $ty {})+
30    };
31}
32
33/// Generate mutual (bidirectional) `Compatible` impls for all unique cross-pairs in a group.
34/// Does NOT generate reflexive impls (those come from `impl_reflexive_compat!`).
35///
36/// `mutual_compat!(A, B, C)` expands to:
37///   Compatible<B> for A, Compatible<A> for B,
38///   Compatible<C> for A, Compatible<A> for C,
39///   Compatible<C> for B, Compatible<B> for C
40macro_rules! mutual_compat {
41    // Entry: dispatch to pair generation
42    ($($ty:ty),+ $(,)?) => {
43        mutual_compat!(@pairs [] $($ty),+);
44    };
45    // Base case: no more types to process
46    (@pairs [$($done:ty),*]) => {};
47    // Recursive case: take first type, pair it with all remaining
48    (@pairs [$($done:ty),*] $first:ty $(, $rest:ty)*) => {
49        $(
50            impl Compatible<$rest> for $first {}
51            impl Compatible<$first> for $rest {}
52        )*
53        mutual_compat!(@pairs [$($done,)* $first] $($rest),*);
54    };
55}
56
57/// Generate bidirectional `Compatible` impls between an "any" type and a list of types.
58macro_rules! any_compat {
59    ($any:ty; $($ty:ty),+ $(,)?) => {
60        $(
61            impl Compatible<$ty> for $any {}
62            impl Compatible<$any> for $ty {}
63        )+
64    };
65}
66
67macro_rules! impl_placeholder_compat {
68    ($($ty:ty),+ $(,)?) => {
69        $(
70            impl Compatible<crate::Placeholder> for $ty {}
71            impl Compatible<$ty> for crate::Placeholder {}
72        )+
73    };
74}
75
76/// Generate directional `Assignable` impls: each source can be assigned to the target.
77/// `assign_to!(Target; Src1, Src2)` → `Assignable<Src1> for Target`, `Assignable<Src2> for Target`
78macro_rules! assign_to {
79    ($target:ty; $($src:ty),+ $(,)?) => {
80        $(impl Assignable<$src> for $target {})+
81    };
82}
83
84/// Generate bidirectional `Assignable` for all cross-pairs in a group (mutual assignment).
85/// Does NOT generate reflexive impls (those come from `impl_reflexive_assign!`).
86macro_rules! mutual_assign {
87    ($($ty:ty),+ $(,)?) => {
88        mutual_assign!(@pairs [] $($ty),+);
89    };
90    (@pairs [$($done:ty),*]) => {};
91    (@pairs [$($done:ty),*] $first:ty $(, $rest:ty)*) => {
92        $(
93            impl Assignable<$rest> for $first {}
94            impl Assignable<$first> for $rest {}
95        )*
96        mutual_assign!(@pairs [$($done,)* $first] $($rest),*);
97    };
98}
99
100/// Generate `Assignable` from every source to a single "any" target.
101macro_rules! any_assign {
102    ($any:ty; $($ty:ty),+ $(,)?) => {
103        $(impl Assignable<$ty> for $any {})+
104    };
105}
106
107// =============================================================================
108// Generic impls
109// =============================================================================
110
111impl<T: DataType> Compatible<Self> for crate::Array<T> {}
112impl Compatible<Self> for crate::Placeholder {}
113impl<T: DataType> Assignable<Self> for crate::Array<T> {}
114
115// Reflexive compat & assign for all concrete types
116impl_reflexive_compat!(
117    crate::sqlite::types::Integer,
118    crate::sqlite::types::Text,
119    crate::sqlite::types::Real,
120    crate::sqlite::types::Blob,
121    crate::sqlite::types::Numeric,
122    crate::sqlite::types::Any,
123    crate::postgres::types::Int2,
124    crate::postgres::types::Int4,
125    crate::postgres::types::Int8,
126    crate::postgres::types::Float4,
127    crate::postgres::types::Float8,
128    crate::postgres::types::Varchar,
129    crate::postgres::types::Text,
130    crate::postgres::types::Char,
131    crate::postgres::types::Bytea,
132    crate::postgres::types::Boolean,
133    crate::postgres::types::Timestamptz,
134    crate::postgres::types::Timestamp,
135    crate::postgres::types::Date,
136    crate::postgres::types::Time,
137    crate::postgres::types::Timetz,
138    crate::postgres::types::Numeric,
139    crate::postgres::types::Uuid,
140    crate::postgres::types::Json,
141    crate::postgres::types::Jsonb,
142    crate::postgres::types::Any,
143    crate::postgres::types::Interval,
144    crate::postgres::types::Inet,
145    crate::postgres::types::Cidr,
146    crate::postgres::types::MacAddr,
147    crate::postgres::types::MacAddr8,
148    crate::postgres::types::Point,
149    crate::postgres::types::LineString,
150    crate::postgres::types::Rect,
151    crate::postgres::types::BitString,
152    crate::postgres::types::Line,
153    crate::postgres::types::LineSegment,
154    crate::postgres::types::Polygon,
155    crate::postgres::types::Circle,
156    crate::postgres::types::Enum,
157    crate::mysql::types::TinyInt,
158    crate::mysql::types::TinyIntUnsigned,
159    crate::mysql::types::SmallInt,
160    crate::mysql::types::SmallIntUnsigned,
161    crate::mysql::types::MediumInt,
162    crate::mysql::types::MediumIntUnsigned,
163    crate::mysql::types::Int,
164    crate::mysql::types::IntUnsigned,
165    crate::mysql::types::BigInt,
166    crate::mysql::types::BigIntUnsigned,
167    crate::mysql::types::Float,
168    crate::mysql::types::Double,
169    crate::mysql::types::Decimal,
170    crate::mysql::types::Boolean,
171    crate::mysql::types::Char,
172    crate::mysql::types::Varchar,
173    crate::mysql::types::TinyText,
174    crate::mysql::types::Text,
175    crate::mysql::types::MediumText,
176    crate::mysql::types::LongText,
177    crate::mysql::types::Binary,
178    crate::mysql::types::Varbinary,
179    crate::mysql::types::TinyBlob,
180    crate::mysql::types::Blob,
181    crate::mysql::types::MediumBlob,
182    crate::mysql::types::LongBlob,
183    crate::mysql::types::Json,
184    crate::mysql::types::Date,
185    crate::mysql::types::Time,
186    crate::mysql::types::DateTime,
187    crate::mysql::types::Timestamp,
188    crate::mysql::types::Year,
189    crate::mysql::types::Enum,
190    crate::mysql::types::Set,
191    crate::mysql::types::Bit,
192    crate::mysql::types::Any,
193);
194
195impl_reflexive_assign!(
196    crate::sqlite::types::Integer,
197    crate::sqlite::types::Text,
198    crate::sqlite::types::Real,
199    crate::sqlite::types::Blob,
200    crate::sqlite::types::Numeric,
201    crate::sqlite::types::Any,
202    crate::postgres::types::Int2,
203    crate::postgres::types::Int4,
204    crate::postgres::types::Int8,
205    crate::postgres::types::Float4,
206    crate::postgres::types::Float8,
207    crate::postgres::types::Varchar,
208    crate::postgres::types::Text,
209    crate::postgres::types::Char,
210    crate::postgres::types::Bytea,
211    crate::postgres::types::Boolean,
212    crate::postgres::types::Timestamptz,
213    crate::postgres::types::Timestamp,
214    crate::postgres::types::Date,
215    crate::postgres::types::Time,
216    crate::postgres::types::Timetz,
217    crate::postgres::types::Numeric,
218    crate::postgres::types::Uuid,
219    crate::postgres::types::Json,
220    crate::postgres::types::Jsonb,
221    crate::postgres::types::Any,
222    crate::postgres::types::Interval,
223    crate::postgres::types::Inet,
224    crate::postgres::types::Cidr,
225    crate::postgres::types::MacAddr,
226    crate::postgres::types::MacAddr8,
227    crate::postgres::types::Point,
228    crate::postgres::types::LineString,
229    crate::postgres::types::Rect,
230    crate::postgres::types::BitString,
231    crate::postgres::types::Line,
232    crate::postgres::types::LineSegment,
233    crate::postgres::types::Polygon,
234    crate::postgres::types::Circle,
235    crate::postgres::types::Enum,
236    crate::mysql::types::TinyInt,
237    crate::mysql::types::TinyIntUnsigned,
238    crate::mysql::types::SmallInt,
239    crate::mysql::types::SmallIntUnsigned,
240    crate::mysql::types::MediumInt,
241    crate::mysql::types::MediumIntUnsigned,
242    crate::mysql::types::Int,
243    crate::mysql::types::IntUnsigned,
244    crate::mysql::types::BigInt,
245    crate::mysql::types::BigIntUnsigned,
246    crate::mysql::types::Float,
247    crate::mysql::types::Double,
248    crate::mysql::types::Decimal,
249    crate::mysql::types::Boolean,
250    crate::mysql::types::Char,
251    crate::mysql::types::Varchar,
252    crate::mysql::types::TinyText,
253    crate::mysql::types::Text,
254    crate::mysql::types::MediumText,
255    crate::mysql::types::LongText,
256    crate::mysql::types::Binary,
257    crate::mysql::types::Varbinary,
258    crate::mysql::types::TinyBlob,
259    crate::mysql::types::Blob,
260    crate::mysql::types::MediumBlob,
261    crate::mysql::types::LongBlob,
262    crate::mysql::types::Json,
263    crate::mysql::types::Date,
264    crate::mysql::types::Time,
265    crate::mysql::types::DateTime,
266    crate::mysql::types::Timestamp,
267    crate::mysql::types::Year,
268    crate::mysql::types::Enum,
269    crate::mysql::types::Set,
270    crate::mysql::types::Bit,
271    crate::mysql::types::Any,
272);
273
274// =============================================================================
275// SQLite compatibility (category-based)
276// =============================================================================
277
278// SQLite numeric family: Integer ↔ Real ↔ Numeric (all mutually compatible)
279mutual_compat!(
280    crate::sqlite::types::Integer,
281    crate::sqlite::types::Real,
282    crate::sqlite::types::Numeric
283);
284
285// Blob ↔ Text (SQLite stores UUIDs, etc. as either)
286mutual_compat!(crate::sqlite::types::Text, crate::sqlite::types::Blob);
287
288// Any ↔ all SQLite types
289any_compat!(crate::sqlite::types::Any;
290    crate::sqlite::types::Integer,
291    crate::sqlite::types::Text,
292    crate::sqlite::types::Real,
293    crate::sqlite::types::Blob,
294    crate::sqlite::types::Numeric
295);
296
297impl_placeholder_compat!(
298    crate::sqlite::types::Integer,
299    crate::sqlite::types::Text,
300    crate::sqlite::types::Real,
301    crate::sqlite::types::Blob,
302    crate::sqlite::types::Numeric,
303    crate::sqlite::types::Any
304);
305
306// =============================================================================
307// PostgreSQL compatibility (category-based)
308// =============================================================================
309
310// Integer family: Int2 ↔ Int4 ↔ Int8 (all mutually compatible)
311mutual_compat!(
312    crate::postgres::types::Int2,
313    crate::postgres::types::Int4,
314    crate::postgres::types::Int8
315);
316
317// Float family: Float4 ↔ Float8
318mutual_compat!(
319    crate::postgres::types::Float4,
320    crate::postgres::types::Float8
321);
322
323// Cross-numeric: all integers ↔ all floats
324// (Int2, Int4, Int8) × (Float4, Float8)
325/// Generate cross-product `Compatible` impls between two groups of types.
326/// Every type in group A becomes compatible with every type in group B (bidirectional).
327macro_rules! cross_compat {
328    ([$first_a:ty $(, $rest_a:ty)* $(,)?], [$($b:ty),+ $(,)?]) => {
329        // Expand first_a × all B
330        $(
331            impl Compatible<$b> for $first_a {}
332            impl Compatible<$first_a> for $b {}
333        )+
334        // Recurse for remaining A types
335        cross_compat!([$($rest_a),*], [$($b),+]);
336    };
337    // Base case: empty A list
338    ([], [$($b:ty),+ $(,)?]) => {};
339}
340
341cross_compat!(
342    [
343        crate::postgres::types::Int2,
344        crate::postgres::types::Int4,
345        crate::postgres::types::Int8
346    ],
347    [
348        crate::postgres::types::Float4,
349        crate::postgres::types::Float8
350    ]
351);
352
353// Numeric ↔ all numeric types (Int2, Int4, Int8, Float4, Float8)
354any_compat!(crate::postgres::types::Numeric;
355    crate::postgres::types::Int2,
356    crate::postgres::types::Int4,
357    crate::postgres::types::Int8,
358    crate::postgres::types::Float4,
359    crate::postgres::types::Float8
360);
361
362// Text family: Text ↔ Varchar ↔ Char (all mutually compatible)
363mutual_compat!(
364    crate::postgres::types::Text,
365    crate::postgres::types::Varchar,
366    crate::postgres::types::Char
367);
368
369// Temporal cross-compatibility pairs
370mutual_compat!(
371    crate::postgres::types::Timestamptz,
372    crate::postgres::types::Timestamp
373);
374mutual_compat!(crate::postgres::types::Time, crate::postgres::types::Timetz);
375
376// JSON cross-compatibility
377mutual_compat!(crate::postgres::types::Json, crate::postgres::types::Jsonb);
378
379// Text ↔ Temporal (string comparisons with timestamps)
380cross_compat!(
381    [crate::postgres::types::Text],
382    [
383        crate::postgres::types::Timestamptz,
384        crate::postgres::types::Timestamp,
385        crate::postgres::types::Date,
386        crate::postgres::types::Time
387    ]
388);
389
390// Network types: Inet ↔ Cidr
391mutual_compat!(crate::postgres::types::Inet, crate::postgres::types::Cidr);
392
393// MAC address types: MacAddr ↔ MacAddr8
394mutual_compat!(
395    crate::postgres::types::MacAddr,
396    crate::postgres::types::MacAddr8
397);
398
399// Enum ↔ Text family
400cross_compat!(
401    [crate::postgres::types::Enum],
402    [
403        crate::postgres::types::Text,
404        crate::postgres::types::Varchar,
405        crate::postgres::types::Char
406    ]
407);
408
409// Any ↔ all PostgreSQL types
410any_compat!(crate::postgres::types::Any;
411    crate::postgres::types::Int2,
412    crate::postgres::types::Int4,
413    crate::postgres::types::Int8,
414    crate::postgres::types::Float4,
415    crate::postgres::types::Float8,
416    crate::postgres::types::Varchar,
417    crate::postgres::types::Text,
418    crate::postgres::types::Char,
419    crate::postgres::types::Bytea,
420    crate::postgres::types::Boolean,
421    crate::postgres::types::Timestamptz,
422    crate::postgres::types::Timestamp,
423    crate::postgres::types::Date,
424    crate::postgres::types::Time,
425    crate::postgres::types::Timetz,
426    crate::postgres::types::Numeric,
427    crate::postgres::types::Uuid,
428    crate::postgres::types::Json,
429    crate::postgres::types::Jsonb,
430    crate::postgres::types::Interval,
431    crate::postgres::types::Inet,
432    crate::postgres::types::Cidr,
433    crate::postgres::types::MacAddr,
434    crate::postgres::types::MacAddr8,
435    crate::postgres::types::Point,
436    crate::postgres::types::LineString,
437    crate::postgres::types::Rect,
438    crate::postgres::types::BitString,
439    crate::postgres::types::Line,
440    crate::postgres::types::LineSegment,
441    crate::postgres::types::Polygon,
442    crate::postgres::types::Circle,
443    crate::postgres::types::Enum
444);
445
446impl_placeholder_compat!(
447    crate::postgres::types::Int2,
448    crate::postgres::types::Int4,
449    crate::postgres::types::Int8,
450    crate::postgres::types::Float4,
451    crate::postgres::types::Float8,
452    crate::postgres::types::Varchar,
453    crate::postgres::types::Text,
454    crate::postgres::types::Char,
455    crate::postgres::types::Bytea,
456    crate::postgres::types::Boolean,
457    crate::postgres::types::Timestamptz,
458    crate::postgres::types::Timestamp,
459    crate::postgres::types::Date,
460    crate::postgres::types::Time,
461    crate::postgres::types::Timetz,
462    crate::postgres::types::Numeric,
463    crate::postgres::types::Uuid,
464    crate::postgres::types::Json,
465    crate::postgres::types::Jsonb,
466    crate::postgres::types::Any,
467    crate::postgres::types::Interval,
468    crate::postgres::types::Inet,
469    crate::postgres::types::Cidr,
470    crate::postgres::types::MacAddr,
471    crate::postgres::types::MacAddr8,
472    crate::postgres::types::Point,
473    crate::postgres::types::LineString,
474    crate::postgres::types::Rect,
475    crate::postgres::types::BitString,
476    crate::postgres::types::Line,
477    crate::postgres::types::LineSegment,
478    crate::postgres::types::Polygon,
479    crate::postgres::types::Circle,
480    crate::postgres::types::Enum
481);
482
483// =============================================================================
484// MySQL compatibility (category-based)
485// =============================================================================
486
487// Keep signed and unsigned integer families distinct. MySQL can coerce between
488// them, but negative signed values have surprising comparison semantics with
489// unsigned values; callers can opt into that behavior with an explicit cast.
490mutual_compat!(
491    crate::mysql::types::TinyInt,
492    crate::mysql::types::SmallInt,
493    crate::mysql::types::MediumInt,
494    crate::mysql::types::Int,
495    crate::mysql::types::BigInt
496);
497mutual_compat!(
498    crate::mysql::types::TinyIntUnsigned,
499    crate::mysql::types::SmallIntUnsigned,
500    crate::mysql::types::MediumIntUnsigned,
501    crate::mysql::types::IntUnsigned,
502    crate::mysql::types::BigIntUnsigned
503);
504
505// YEAR is numeric and has a restricted domain, so it may be compared with
506// either integer family without implying compatibility between those families.
507cross_compat!(
508    [crate::mysql::types::Year],
509    [
510        crate::mysql::types::TinyInt,
511        crate::mysql::types::SmallInt,
512        crate::mysql::types::MediumInt,
513        crate::mysql::types::Int,
514        crate::mysql::types::BigInt,
515        crate::mysql::types::TinyIntUnsigned,
516        crate::mysql::types::SmallIntUnsigned,
517        crate::mysql::types::MediumIntUnsigned,
518        crate::mysql::types::IntUnsigned,
519        crate::mysql::types::BigIntUnsigned
520    ]
521);
522
523// Exact and approximate numeric types can be compared with every integer
524// marker; FLOAT, DOUBLE, and DECIMAL are also mutually compatible.
525cross_compat!(
526    [
527        crate::mysql::types::TinyInt,
528        crate::mysql::types::SmallInt,
529        crate::mysql::types::MediumInt,
530        crate::mysql::types::Int,
531        crate::mysql::types::BigInt,
532        crate::mysql::types::TinyIntUnsigned,
533        crate::mysql::types::SmallIntUnsigned,
534        crate::mysql::types::MediumIntUnsigned,
535        crate::mysql::types::IntUnsigned,
536        crate::mysql::types::BigIntUnsigned,
537        crate::mysql::types::Year
538    ],
539    [
540        crate::mysql::types::Decimal,
541        crate::mysql::types::Float,
542        crate::mysql::types::Double
543    ]
544);
545mutual_compat!(
546    crate::mysql::types::Decimal,
547    crate::mysql::types::Float,
548    crate::mysql::types::Double
549);
550
551// Text families are mutually comparable. ENUM and SET are textual values, but
552// remain distinct from each other because SET's comma-separated representation
553// has different semantics.
554mutual_compat!(
555    crate::mysql::types::Char,
556    crate::mysql::types::Varchar,
557    crate::mysql::types::TinyText,
558    crate::mysql::types::Text,
559    crate::mysql::types::MediumText,
560    crate::mysql::types::LongText
561);
562cross_compat!(
563    [crate::mysql::types::Enum],
564    [
565        crate::mysql::types::Char,
566        crate::mysql::types::Varchar,
567        crate::mysql::types::TinyText,
568        crate::mysql::types::Text,
569        crate::mysql::types::MediumText,
570        crate::mysql::types::LongText
571    ]
572);
573cross_compat!(
574    [crate::mysql::types::Set],
575    [
576        crate::mysql::types::Char,
577        crate::mysql::types::Varchar,
578        crate::mysql::types::TinyText,
579        crate::mysql::types::Text,
580        crate::mysql::types::MediumText,
581        crate::mysql::types::LongText
582    ]
583);
584
585// All binary families, including BIT's packed bytes, are mutually comparable.
586mutual_compat!(
587    crate::mysql::types::Binary,
588    crate::mysql::types::Varbinary,
589    crate::mysql::types::TinyBlob,
590    crate::mysql::types::Blob,
591    crate::mysql::types::MediumBlob,
592    crate::mysql::types::LongBlob,
593    crate::mysql::types::Bit
594);
595
596// DATETIME and TIMESTAMP represent the same wall-clock shape at the SQL type
597// level, while preserving their distinct storage semantics elsewhere.
598mutual_compat!(
599    crate::mysql::types::DateTime,
600    crate::mysql::types::Timestamp
601);
602
603// Any ↔ all MySQL types.
604any_compat!(crate::mysql::types::Any;
605    crate::mysql::types::TinyInt,
606    crate::mysql::types::TinyIntUnsigned,
607    crate::mysql::types::SmallInt,
608    crate::mysql::types::SmallIntUnsigned,
609    crate::mysql::types::MediumInt,
610    crate::mysql::types::MediumIntUnsigned,
611    crate::mysql::types::Int,
612    crate::mysql::types::IntUnsigned,
613    crate::mysql::types::BigInt,
614    crate::mysql::types::BigIntUnsigned,
615    crate::mysql::types::Float,
616    crate::mysql::types::Double,
617    crate::mysql::types::Decimal,
618    crate::mysql::types::Boolean,
619    crate::mysql::types::Char,
620    crate::mysql::types::Varchar,
621    crate::mysql::types::TinyText,
622    crate::mysql::types::Text,
623    crate::mysql::types::MediumText,
624    crate::mysql::types::LongText,
625    crate::mysql::types::Binary,
626    crate::mysql::types::Varbinary,
627    crate::mysql::types::TinyBlob,
628    crate::mysql::types::Blob,
629    crate::mysql::types::MediumBlob,
630    crate::mysql::types::LongBlob,
631    crate::mysql::types::Json,
632    crate::mysql::types::Date,
633    crate::mysql::types::Time,
634    crate::mysql::types::DateTime,
635    crate::mysql::types::Timestamp,
636    crate::mysql::types::Year,
637    crate::mysql::types::Enum,
638    crate::mysql::types::Set,
639    crate::mysql::types::Bit
640);
641
642impl_placeholder_compat!(
643    crate::mysql::types::TinyInt,
644    crate::mysql::types::TinyIntUnsigned,
645    crate::mysql::types::SmallInt,
646    crate::mysql::types::SmallIntUnsigned,
647    crate::mysql::types::MediumInt,
648    crate::mysql::types::MediumIntUnsigned,
649    crate::mysql::types::Int,
650    crate::mysql::types::IntUnsigned,
651    crate::mysql::types::BigInt,
652    crate::mysql::types::BigIntUnsigned,
653    crate::mysql::types::Float,
654    crate::mysql::types::Double,
655    crate::mysql::types::Decimal,
656    crate::mysql::types::Boolean,
657    crate::mysql::types::Char,
658    crate::mysql::types::Varchar,
659    crate::mysql::types::TinyText,
660    crate::mysql::types::Text,
661    crate::mysql::types::MediumText,
662    crate::mysql::types::LongText,
663    crate::mysql::types::Binary,
664    crate::mysql::types::Varbinary,
665    crate::mysql::types::TinyBlob,
666    crate::mysql::types::Blob,
667    crate::mysql::types::MediumBlob,
668    crate::mysql::types::LongBlob,
669    crate::mysql::types::Json,
670    crate::mysql::types::Date,
671    crate::mysql::types::Time,
672    crate::mysql::types::DateTime,
673    crate::mysql::types::Timestamp,
674    crate::mysql::types::Year,
675    crate::mysql::types::Enum,
676    crate::mysql::types::Set,
677    crate::mysql::types::Bit,
678    crate::mysql::types::Any
679);
680
681// =============================================================================
682// Assignment compatibility (bind-time)
683// =============================================================================
684// Assignment is stricter than comparison: only wider types accept narrower values.
685
686// SQLite assignment
687assign_to!(crate::sqlite::types::Real; crate::sqlite::types::Integer);
688assign_to!(crate::sqlite::types::Numeric; crate::sqlite::types::Integer, crate::sqlite::types::Real);
689any_assign!(crate::sqlite::types::Any;
690    crate::sqlite::types::Integer,
691    crate::sqlite::types::Text,
692    crate::sqlite::types::Real,
693    crate::sqlite::types::Blob,
694    crate::sqlite::types::Numeric
695);
696
697// PostgreSQL integer widening: Int2 → Int4 → Int8
698assign_to!(crate::postgres::types::Int4; crate::postgres::types::Int2);
699assign_to!(crate::postgres::types::Int8; crate::postgres::types::Int2, crate::postgres::types::Int4);
700
701// Int → Float widening
702assign_to!(crate::postgres::types::Float4;
703    crate::postgres::types::Int2,
704    crate::postgres::types::Int4,
705    crate::postgres::types::Int8
706);
707assign_to!(crate::postgres::types::Float8;
708    crate::postgres::types::Int2,
709    crate::postgres::types::Int4,
710    crate::postgres::types::Int8,
711    crate::postgres::types::Float4
712);
713
714// Numeric accepts all numeric types
715assign_to!(crate::postgres::types::Numeric;
716    crate::postgres::types::Int2,
717    crate::postgres::types::Int4,
718    crate::postgres::types::Int8,
719    crate::postgres::types::Float4,
720    crate::postgres::types::Float8
721);
722
723// Text family: all mutually assignable
724mutual_assign!(
725    crate::postgres::types::Text,
726    crate::postgres::types::Varchar,
727    crate::postgres::types::Char
728);
729
730// Enum → Text family
731assign_to!(crate::postgres::types::Varchar; crate::postgres::types::Enum);
732assign_to!(crate::postgres::types::Text; crate::postgres::types::Enum);
733assign_to!(crate::postgres::types::Char; crate::postgres::types::Enum);
734
735// Temporal and JSON assignment
736assign_to!(crate::postgres::types::Timestamptz; crate::postgres::types::Timestamp);
737assign_to!(crate::postgres::types::Timetz; crate::postgres::types::Time);
738assign_to!(crate::postgres::types::Jsonb; crate::postgres::types::Json);
739
740// Network assignment
741assign_to!(crate::postgres::types::Cidr; crate::postgres::types::Inet);
742
743// Any accepts all concrete PostgreSQL markers
744any_assign!(crate::postgres::types::Any;
745    crate::postgres::types::Int2,
746    crate::postgres::types::Int4,
747    crate::postgres::types::Int8,
748    crate::postgres::types::Float4,
749    crate::postgres::types::Float8,
750    crate::postgres::types::Varchar,
751    crate::postgres::types::Text,
752    crate::postgres::types::Char,
753    crate::postgres::types::Bytea,
754    crate::postgres::types::Boolean,
755    crate::postgres::types::Timestamptz,
756    crate::postgres::types::Timestamp,
757    crate::postgres::types::Date,
758    crate::postgres::types::Time,
759    crate::postgres::types::Timetz,
760    crate::postgres::types::Numeric,
761    crate::postgres::types::Uuid,
762    crate::postgres::types::Json,
763    crate::postgres::types::Jsonb,
764    crate::postgres::types::Interval,
765    crate::postgres::types::Inet,
766    crate::postgres::types::Cidr,
767    crate::postgres::types::MacAddr,
768    crate::postgres::types::MacAddr8,
769    crate::postgres::types::Point,
770    crate::postgres::types::LineString,
771    crate::postgres::types::Rect,
772    crate::postgres::types::BitString,
773    crate::postgres::types::Line,
774    crate::postgres::types::LineSegment,
775    crate::postgres::types::Polygon,
776    crate::postgres::types::Circle,
777    crate::postgres::types::Enum
778);
779
780// MySQL integer widening. Unsigned sources are accepted by a signed target
781// only when the entire source range fits in that target. The reverse direction
782// is deliberately absent because negative values cannot be represented.
783assign_to!(crate::mysql::types::SmallInt;
784    crate::mysql::types::TinyInt,
785    crate::mysql::types::TinyIntUnsigned
786);
787assign_to!(crate::mysql::types::MediumInt;
788    crate::mysql::types::TinyInt,
789    crate::mysql::types::SmallInt,
790    // Rust has no 24-bit integer. Selected MEDIUMINT values use i32, whose
791    // dialect marker is INT, and the server validates the column range.
792    crate::mysql::types::Int,
793    crate::mysql::types::TinyIntUnsigned,
794    crate::mysql::types::SmallIntUnsigned,
795    crate::mysql::types::Year
796);
797assign_to!(crate::mysql::types::Int;
798    crate::mysql::types::TinyInt,
799    crate::mysql::types::SmallInt,
800    crate::mysql::types::MediumInt,
801    crate::mysql::types::TinyIntUnsigned,
802    crate::mysql::types::SmallIntUnsigned,
803    crate::mysql::types::MediumIntUnsigned,
804    crate::mysql::types::Year
805);
806assign_to!(crate::mysql::types::BigInt;
807    crate::mysql::types::TinyInt,
808    crate::mysql::types::SmallInt,
809    crate::mysql::types::MediumInt,
810    crate::mysql::types::Int,
811    crate::mysql::types::TinyIntUnsigned,
812    crate::mysql::types::SmallIntUnsigned,
813    crate::mysql::types::MediumIntUnsigned,
814    crate::mysql::types::IntUnsigned,
815    crate::mysql::types::Year
816);
817assign_to!(crate::mysql::types::SmallIntUnsigned;
818    crate::mysql::types::TinyIntUnsigned,
819    crate::mysql::types::Year
820);
821assign_to!(crate::mysql::types::MediumIntUnsigned;
822    crate::mysql::types::TinyIntUnsigned,
823    crate::mysql::types::SmallIntUnsigned,
824    // Rust has no 24-bit unsigned integer; see the signed case above.
825    crate::mysql::types::IntUnsigned,
826    crate::mysql::types::Year
827);
828assign_to!(crate::mysql::types::IntUnsigned;
829    crate::mysql::types::TinyIntUnsigned,
830    crate::mysql::types::SmallIntUnsigned,
831    crate::mysql::types::MediumIntUnsigned,
832    crate::mysql::types::Year
833);
834assign_to!(crate::mysql::types::BigIntUnsigned;
835    crate::mysql::types::TinyIntUnsigned,
836    crate::mysql::types::SmallIntUnsigned,
837    crate::mysql::types::MediumIntUnsigned,
838    crate::mysql::types::IntUnsigned,
839    crate::mysql::types::Year
840);
841// Rust represents YEAR as u16, whose dialect value marker is
842// SmallIntUnsigned. The server remains responsible for YEAR's narrower
843// calendar domain (the same way it validates VARCHAR lengths and DECIMAL
844// precision).
845assign_to!(crate::mysql::types::Year; crate::mysql::types::SmallIntUnsigned);
846
847// Numeric targets follow the existing PostgreSQL policy: exact integers may be
848// bound to floating and decimal columns, and FLOAT widens to DOUBLE. DECIMAL
849// also accepts approximate values because MySQL performs that conversion.
850assign_to!(crate::mysql::types::Float;
851    crate::mysql::types::TinyInt,
852    crate::mysql::types::SmallInt,
853    crate::mysql::types::MediumInt,
854    crate::mysql::types::Int,
855    crate::mysql::types::BigInt,
856    crate::mysql::types::TinyIntUnsigned,
857    crate::mysql::types::SmallIntUnsigned,
858    crate::mysql::types::MediumIntUnsigned,
859    crate::mysql::types::IntUnsigned,
860    crate::mysql::types::BigIntUnsigned,
861    crate::mysql::types::Year
862);
863assign_to!(crate::mysql::types::Double;
864    crate::mysql::types::TinyInt,
865    crate::mysql::types::SmallInt,
866    crate::mysql::types::MediumInt,
867    crate::mysql::types::Int,
868    crate::mysql::types::BigInt,
869    crate::mysql::types::TinyIntUnsigned,
870    crate::mysql::types::SmallIntUnsigned,
871    crate::mysql::types::MediumIntUnsigned,
872    crate::mysql::types::IntUnsigned,
873    crate::mysql::types::BigIntUnsigned,
874    crate::mysql::types::Year,
875    crate::mysql::types::Float
876);
877assign_to!(crate::mysql::types::Decimal;
878    crate::mysql::types::TinyInt,
879    crate::mysql::types::SmallInt,
880    crate::mysql::types::MediumInt,
881    crate::mysql::types::Int,
882    crate::mysql::types::BigInt,
883    crate::mysql::types::TinyIntUnsigned,
884    crate::mysql::types::SmallIntUnsigned,
885    crate::mysql::types::MediumIntUnsigned,
886    crate::mysql::types::IntUnsigned,
887    crate::mysql::types::BigIntUnsigned,
888    crate::mysql::types::Year,
889    crate::mysql::types::Float,
890    crate::mysql::types::Double
891);
892
893// When optional domain crates are disabled, rows decode these values as
894// strings. Accepting Text closes that intentional feature-off round trip; the
895// MySQL server remains the parser and validator at the database boundary.
896assign_to!(crate::mysql::types::Decimal; crate::mysql::types::Text);
897assign_to!(crate::mysql::types::Json; crate::mysql::types::Text);
898assign_to!(crate::mysql::types::Date; crate::mysql::types::Text);
899assign_to!(crate::mysql::types::Time; crate::mysql::types::Text);
900assign_to!(crate::mysql::types::DateTime; crate::mysql::types::Text);
901assign_to!(crate::mysql::types::Timestamp; crate::mysql::types::Text);
902
903// Text and binary storage families are interchangeable at bind time. MySQL
904// validates inline ENUM and SET membership at the column boundary, so their
905// generated Rust string values must be accepted as text inputs here.
906mutual_assign!(
907    crate::mysql::types::Char,
908    crate::mysql::types::Varchar,
909    crate::mysql::types::TinyText,
910    crate::mysql::types::Text,
911    crate::mysql::types::MediumText,
912    crate::mysql::types::LongText
913);
914assign_to!(crate::mysql::types::Char;
915    crate::mysql::types::Enum,
916    crate::mysql::types::Set
917);
918assign_to!(crate::mysql::types::Varchar;
919    crate::mysql::types::Enum,
920    crate::mysql::types::Set
921);
922assign_to!(crate::mysql::types::TinyText;
923    crate::mysql::types::Enum,
924    crate::mysql::types::Set
925);
926assign_to!(crate::mysql::types::Text;
927    crate::mysql::types::Enum,
928    crate::mysql::types::Set
929);
930assign_to!(crate::mysql::types::MediumText;
931    crate::mysql::types::Enum,
932    crate::mysql::types::Set
933);
934assign_to!(crate::mysql::types::LongText;
935    crate::mysql::types::Enum,
936    crate::mysql::types::Set
937);
938assign_to!(crate::mysql::types::Enum;
939    crate::mysql::types::Char,
940    crate::mysql::types::Varchar,
941    crate::mysql::types::TinyText,
942    crate::mysql::types::Text,
943    crate::mysql::types::MediumText,
944    crate::mysql::types::LongText
945);
946assign_to!(crate::mysql::types::Set;
947    crate::mysql::types::Char,
948    crate::mysql::types::Varchar,
949    crate::mysql::types::TinyText,
950    crate::mysql::types::Text,
951    crate::mysql::types::MediumText,
952    crate::mysql::types::LongText
953);
954mutual_assign!(
955    crate::mysql::types::Binary,
956    crate::mysql::types::Varbinary,
957    crate::mysql::types::TinyBlob,
958    crate::mysql::types::Blob,
959    crate::mysql::types::MediumBlob,
960    crate::mysql::types::LongBlob,
961    crate::mysql::types::Bit
962);
963// BIT may retain its packed bytes through the binary family above or decode as
964// an unsigned integer (and as bool for BIT(1)). MySQL validates the declared
965// bit width at the column boundary.
966assign_to!(crate::mysql::types::Bit;
967    crate::mysql::types::Boolean,
968    crate::mysql::types::TinyIntUnsigned,
969    crate::mysql::types::SmallIntUnsigned,
970    crate::mysql::types::MediumIntUnsigned,
971    crate::mysql::types::IntUnsigned,
972    crate::mysql::types::BigIntUnsigned
973);
974
975// Any accepts all concrete MySQL markers.
976any_assign!(crate::mysql::types::Any;
977    crate::mysql::types::TinyInt,
978    crate::mysql::types::TinyIntUnsigned,
979    crate::mysql::types::SmallInt,
980    crate::mysql::types::SmallIntUnsigned,
981    crate::mysql::types::MediumInt,
982    crate::mysql::types::MediumIntUnsigned,
983    crate::mysql::types::Int,
984    crate::mysql::types::IntUnsigned,
985    crate::mysql::types::BigInt,
986    crate::mysql::types::BigIntUnsigned,
987    crate::mysql::types::Float,
988    crate::mysql::types::Double,
989    crate::mysql::types::Decimal,
990    crate::mysql::types::Boolean,
991    crate::mysql::types::Char,
992    crate::mysql::types::Varchar,
993    crate::mysql::types::TinyText,
994    crate::mysql::types::Text,
995    crate::mysql::types::MediumText,
996    crate::mysql::types::LongText,
997    crate::mysql::types::Binary,
998    crate::mysql::types::Varbinary,
999    crate::mysql::types::TinyBlob,
1000    crate::mysql::types::Blob,
1001    crate::mysql::types::MediumBlob,
1002    crate::mysql::types::LongBlob,
1003    crate::mysql::types::Json,
1004    crate::mysql::types::Date,
1005    crate::mysql::types::Time,
1006    crate::mysql::types::DateTime,
1007    crate::mysql::types::Timestamp,
1008    crate::mysql::types::Year,
1009    crate::mysql::types::Enum,
1010    crate::mysql::types::Set,
1011    crate::mysql::types::Bit
1012);
1013
1014// =============================================================================
1015// Tuple compatibility
1016// =============================================================================
1017
1018macro_rules! seq_dual {
1019    (@acc $callback:ident [$($sa:ident),*] [$($da:ident),*]) => {};
1020    (@acc $callback:ident [$($sa:ident),*] [$($da:ident),*] ($s:ident, $d:ident) $($rest:tt)*) => {
1021        $callback!($($sa,)* $s; $($da,)* $d);
1022        seq_dual!(@acc $callback [$($sa,)* $s] [$($da,)* $d] $($rest)*);
1023    };
1024    ($callback:ident; $($pairs:tt)+) => {
1025        seq_dual!(@acc $callback [] [] $($pairs)+);
1026    };
1027    (@from $callback:ident [$($sa:ident),*] [$($da:ident),*]; $($pairs:tt)+) => {
1028        seq_dual!(@acc $callback [$($sa),*] [$($da),*] $($pairs)+);
1029    };
1030}
1031
1032macro_rules! with_dual_col_sizes_8 {
1033    ($callback:ident) => {
1034        seq_dual!($callback;
1035            (T0,U0) (T1,U1) (T2,U2) (T3,U3)
1036            (T4,U4) (T5,U5) (T6,U6) (T7,U7)
1037        );
1038    };
1039}
1040
1041#[allow(unused_macros)]
1042macro_rules! with_dual_col_sizes_16 {
1043    ($callback:ident) => {
1044        seq_dual!(@from $callback
1045            [T0,T1,T2,T3,T4,T5,T6,T7]
1046            [U0,U1,U2,U3,U4,U5,U6,U7];
1047            (T8,U8) (T9,U9) (T10,U10) (T11,U11)
1048            (T12,U12) (T13,U13) (T14,U14) (T15,U15)
1049        );
1050    };
1051}
1052
1053#[allow(unused_macros)]
1054macro_rules! with_dual_col_sizes_32 {
1055    ($callback:ident) => {
1056        seq_dual!(@from $callback
1057            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15]
1058            [U0,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,U11,U12,U13,U14,U15];
1059            (T16,U16) (T17,U17) (T18,U18) (T19,U19)
1060            (T20,U20) (T21,U21) (T22,U22) (T23,U23)
1061            (T24,U24) (T25,U25) (T26,U26) (T27,U27)
1062            (T28,U28) (T29,U29) (T30,U30) (T31,U31)
1063        );
1064    };
1065}
1066
1067#[allow(unused_macros)]
1068macro_rules! with_dual_col_sizes_64 {
1069    ($callback:ident) => {
1070        seq_dual!(@from $callback
1071            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
1072             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31]
1073            [U0,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,U11,U12,U13,U14,U15,
1074             U16,U17,U18,U19,U20,U21,U22,U23,U24,U25,U26,U27,U28,U29,U30,U31];
1075            (T32,U32) (T33,U33) (T34,U34) (T35,U35)
1076            (T36,U36) (T37,U37) (T38,U38) (T39,U39)
1077            (T40,U40) (T41,U41) (T42,U42) (T43,U43)
1078            (T44,U44) (T45,U45) (T46,U46) (T47,U47)
1079            (T48,U48) (T49,U49) (T50,U50) (T51,U51)
1080            (T52,U52) (T53,U53) (T54,U54) (T55,U55)
1081            (T56,U56) (T57,U57) (T58,U58) (T59,U59)
1082            (T60,U60) (T61,U61) (T62,U62) (T63,U63)
1083        );
1084    };
1085}
1086
1087#[allow(unused_macros)]
1088macro_rules! with_dual_col_sizes_128 {
1089    ($callback:ident) => {
1090        seq_dual!(@from $callback
1091            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
1092             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,
1093             T32,T33,T34,T35,T36,T37,T38,T39,T40,T41,T42,T43,T44,T45,T46,T47,
1094             T48,T49,T50,T51,T52,T53,T54,T55,T56,T57,T58,T59,T60,T61,T62,T63]
1095            [U0,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,U11,U12,U13,U14,U15,
1096             U16,U17,U18,U19,U20,U21,U22,U23,U24,U25,U26,U27,U28,U29,U30,U31,
1097             U32,U33,U34,U35,U36,U37,U38,U39,U40,U41,U42,U43,U44,U45,U46,U47,
1098             U48,U49,U50,U51,U52,U53,U54,U55,U56,U57,U58,U59,U60,U61,U62,U63];
1099            (T64,U64) (T65,U65) (T66,U66) (T67,U67)
1100            (T68,U68) (T69,U69) (T70,U70) (T71,U71)
1101            (T72,U72) (T73,U73) (T74,U74) (T75,U75)
1102            (T76,U76) (T77,U77) (T78,U78) (T79,U79)
1103            (T80,U80) (T81,U81) (T82,U82) (T83,U83)
1104            (T84,U84) (T85,U85) (T86,U86) (T87,U87)
1105            (T88,U88) (T89,U89) (T90,U90) (T91,U91)
1106            (T92,U92) (T93,U93) (T94,U94) (T95,U95)
1107            (T96,U96) (T97,U97) (T98,U98) (T99,U99)
1108            (T100,U100) (T101,U101) (T102,U102) (T103,U103)
1109            (T104,U104) (T105,U105) (T106,U106) (T107,U107)
1110            (T108,U108) (T109,U109) (T110,U110) (T111,U111)
1111            (T112,U112) (T113,U113) (T114,U114) (T115,U115)
1112            (T116,U116) (T117,U117) (T118,U118) (T119,U119)
1113            (T120,U120) (T121,U121) (T122,U122) (T123,U123)
1114            (T124,U124) (T125,U125) (T126,U126) (T127,U127)
1115        );
1116    };
1117}
1118
1119#[allow(unused_macros)]
1120macro_rules! with_dual_col_sizes_200 {
1121    ($callback:ident) => {
1122        seq_dual!(@from $callback
1123            [T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,
1124             T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,
1125             T32,T33,T34,T35,T36,T37,T38,T39,T40,T41,T42,T43,T44,T45,T46,T47,
1126             T48,T49,T50,T51,T52,T53,T54,T55,T56,T57,T58,T59,T60,T61,T62,T63,
1127             T64,T65,T66,T67,T68,T69,T70,T71,T72,T73,T74,T75,T76,T77,T78,T79,
1128             T80,T81,T82,T83,T84,T85,T86,T87,T88,T89,T90,T91,T92,T93,T94,T95,
1129             T96,T97,T98,T99,T100,T101,T102,T103,T104,T105,T106,T107,T108,T109,T110,T111,
1130             T112,T113,T114,T115,T116,T117,T118,T119,T120,T121,T122,T123,T124,T125,T126,T127]
1131            [U0,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,U11,U12,U13,U14,U15,
1132             U16,U17,U18,U19,U20,U21,U22,U23,U24,U25,U26,U27,U28,U29,U30,U31,
1133             U32,U33,U34,U35,U36,U37,U38,U39,U40,U41,U42,U43,U44,U45,U46,U47,
1134             U48,U49,U50,U51,U52,U53,U54,U55,U56,U57,U58,U59,U60,U61,U62,U63,
1135             U64,U65,U66,U67,U68,U69,U70,U71,U72,U73,U74,U75,U76,U77,U78,U79,
1136             U80,U81,U82,U83,U84,U85,U86,U87,U88,U89,U90,U91,U92,U93,U94,U95,
1137             U96,U97,U98,U99,U100,U101,U102,U103,U104,U105,U106,U107,U108,U109,U110,U111,
1138             U112,U113,U114,U115,U116,U117,U118,U119,U120,U121,U122,U123,U124,U125,U126,U127];
1139            (T128,U128) (T129,U129) (T130,U130) (T131,U131)
1140            (T132,U132) (T133,U133) (T134,U134) (T135,U135)
1141            (T136,U136) (T137,U137) (T138,U138) (T139,U139)
1142            (T140,U140) (T141,U141) (T142,U142) (T143,U143)
1143            (T144,U144) (T145,U145) (T146,U146) (T147,U147)
1144            (T148,U148) (T149,U149) (T150,U150) (T151,U151)
1145            (T152,U152) (T153,U153) (T154,U154) (T155,U155)
1146            (T156,U156) (T157,U157) (T158,U158) (T159,U159)
1147            (T160,U160) (T161,U161) (T162,U162) (T163,U163)
1148            (T164,U164) (T165,U165) (T166,U166) (T167,U167)
1149            (T168,U168) (T169,U169) (T170,U170) (T171,U171)
1150            (T172,U172) (T173,U173) (T174,U174) (T175,U175)
1151            (T176,U176) (T177,U177) (T178,U178) (T179,U179)
1152            (T180,U180) (T181,U181) (T182,U182) (T183,U183)
1153            (T184,U184) (T185,U185) (T186,U186) (T187,U187)
1154            (T188,U188) (T189,U189) (T190,U190) (T191,U191)
1155            (T192,U192) (T193,U193) (T194,U194) (T195,U195)
1156            (T196,U196) (T197,U197) (T198,U198) (T199,U199)
1157        );
1158    };
1159}
1160
1161macro_rules! impl_tuple_compatible {
1162    ($($T:ident),+; $($U:ident),+) => {
1163        impl<$($T, $U),+> Compatible<($($U,)+)> for ($($T,)+)
1164        where
1165            $($T: DataType + Compatible<$U>, $U: DataType,)+
1166        {}
1167    };
1168}
1169
1170macro_rules! impl_tuple_assignable {
1171    ($($S:ident),+; $($D:ident),+) => {
1172        impl<$($S, $D),+> Assignable<($($S,)+)> for ($($D,)+)
1173        where
1174            $($S: DataType, $D: DataType + Assignable<$S>,)+
1175        {}
1176    };
1177}
1178
1179with_dual_col_sizes_8!(impl_tuple_compatible);
1180
1181#[cfg(any(
1182    feature = "col16",
1183    feature = "col32",
1184    feature = "col64",
1185    feature = "col128",
1186    feature = "col200"
1187))]
1188with_dual_col_sizes_16!(impl_tuple_compatible);
1189
1190#[cfg(any(
1191    feature = "col32",
1192    feature = "col64",
1193    feature = "col128",
1194    feature = "col200"
1195))]
1196with_dual_col_sizes_32!(impl_tuple_compatible);
1197
1198#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1199with_dual_col_sizes_64!(impl_tuple_compatible);
1200
1201#[cfg(any(feature = "col128", feature = "col200"))]
1202with_dual_col_sizes_128!(impl_tuple_compatible);
1203
1204#[cfg(feature = "col200")]
1205with_dual_col_sizes_200!(impl_tuple_compatible);
1206
1207with_dual_col_sizes_8!(impl_tuple_assignable);
1208
1209#[cfg(any(
1210    feature = "col16",
1211    feature = "col32",
1212    feature = "col64",
1213    feature = "col128",
1214    feature = "col200"
1215))]
1216with_dual_col_sizes_16!(impl_tuple_assignable);
1217
1218#[cfg(any(
1219    feature = "col32",
1220    feature = "col64",
1221    feature = "col128",
1222    feature = "col200"
1223))]
1224with_dual_col_sizes_32!(impl_tuple_assignable);
1225
1226#[cfg(any(feature = "col64", feature = "col128", feature = "col200"))]
1227with_dual_col_sizes_64!(impl_tuple_assignable);
1228
1229#[cfg(any(feature = "col128", feature = "col200"))]
1230with_dual_col_sizes_128!(impl_tuple_assignable);
1231
1232#[cfg(feature = "col200")]
1233with_dual_col_sizes_200!(impl_tuple_assignable);
1234
1235#[cfg(test)]
1236mod tests {
1237    use super::{Assignable, Compatible, DataType};
1238
1239    fn assert_compatible<L, R>()
1240    where
1241        L: Compatible<R>,
1242        R: DataType,
1243    {
1244    }
1245
1246    fn assert_assignable<Target, Source>()
1247    where
1248        Target: Assignable<Source>,
1249        Source: DataType,
1250    {
1251    }
1252
1253    #[test]
1254    fn mysql_compatibility_covers_the_intended_type_families() {
1255        assert_compatible::<crate::mysql::types::TinyInt, crate::mysql::types::BigInt>();
1256        assert_compatible::<
1257            crate::mysql::types::TinyIntUnsigned,
1258            crate::mysql::types::BigIntUnsigned,
1259        >();
1260        assert_compatible::<crate::mysql::types::Year, crate::mysql::types::Int>();
1261        assert_compatible::<crate::mysql::types::Decimal, crate::mysql::types::Double>();
1262        assert_compatible::<crate::mysql::types::Enum, crate::mysql::types::Text>();
1263        assert_compatible::<crate::mysql::types::Set, crate::mysql::types::Varchar>();
1264        assert_compatible::<crate::mysql::types::Bit, crate::mysql::types::Blob>();
1265        assert_compatible::<crate::mysql::types::DateTime, crate::mysql::types::Timestamp>();
1266        assert_compatible::<crate::mysql::types::Any, crate::mysql::types::Json>();
1267        assert_compatible::<crate::Placeholder, crate::mysql::types::Json>();
1268    }
1269
1270    #[test]
1271    fn mysql_assignment_allows_widening_and_storage_families() {
1272        assert_assignable::<crate::mysql::types::SmallInt, crate::mysql::types::TinyIntUnsigned>();
1273        assert_assignable::<crate::mysql::types::MediumInt, crate::mysql::types::Int>();
1274        assert_assignable::<crate::mysql::types::MediumIntUnsigned, crate::mysql::types::IntUnsigned>(
1275        );
1276        assert_assignable::<crate::mysql::types::BigInt, crate::mysql::types::IntUnsigned>();
1277        assert_assignable::<crate::mysql::types::BigIntUnsigned, crate::mysql::types::IntUnsigned>(
1278        );
1279        assert_assignable::<crate::mysql::types::Decimal, crate::mysql::types::BigIntUnsigned>();
1280        assert_assignable::<crate::mysql::types::Text, crate::mysql::types::Enum>();
1281        assert_assignable::<crate::mysql::types::Enum, crate::mysql::types::Text>();
1282        assert_assignable::<crate::mysql::types::Set, crate::mysql::types::Text>();
1283        assert_assignable::<crate::mysql::types::Year, crate::mysql::types::SmallIntUnsigned>();
1284        assert_assignable::<crate::mysql::types::Bit, crate::mysql::types::Blob>();
1285        assert_assignable::<crate::mysql::types::Bit, crate::mysql::types::Boolean>();
1286        assert_assignable::<crate::mysql::types::Bit, crate::mysql::types::BigIntUnsigned>();
1287        assert_assignable::<crate::mysql::types::Json, crate::mysql::types::Text>();
1288        assert_assignable::<crate::mysql::types::Time, crate::mysql::types::Text>();
1289        assert_assignable::<crate::mysql::types::Any, crate::mysql::types::Json>();
1290    }
1291}