diesel/pg/query_builder/copy/
mod.rs

1use crate::pg::Pg;
2use crate::query_builder::nodes::StaticQueryFragment;
3use crate::query_builder::ColumnList;
4use crate::query_builder::QueryFragment;
5use crate::sql_types::SqlType;
6use crate::Expression;
7use crate::{Column, Table};
8
9pub(crate) mod copy_from;
10pub(crate) mod copy_to;
11
12#[cfg(feature = "postgres")]
13pub(crate) use self::copy_from::{CopyFromExpression, InternalCopyFromQuery};
14#[cfg(feature = "postgres")]
15pub(crate) use self::copy_to::CopyToCommand;
16
17pub use self::copy_from::{CopyFromQuery, CopyHeader, ExecuteCopyFromDsl};
18pub use self::copy_to::CopyToQuery;
19
20const COPY_MAGIC_HEADER: [u8; 11] = [
21    0x50, 0x47, 0x43, 0x4F, 0x50, 0x59, 0x0A, 0xFF, 0x0D, 0x0A, 0x00,
22];
23
24/// Describes the format used by `COPY FROM` or `COPY TO`
25/// statements
26///
27/// See [the postgresql documentation](https://www.postgresql.org/docs/current/sql-copy.html)
28/// for details about the different formats
29#[derive(#[automatically_derived]
impl ::core::default::Default for CopyFormat {
    #[inline]
    fn default() -> CopyFormat { Self::Text }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for CopyFormat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                CopyFormat::Text => "Text",
                CopyFormat::Csv => "Csv",
                CopyFormat::Binary => "Binary",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for CopyFormat { }Copy, #[automatically_derived]
impl ::core::clone::Clone for CopyFormat {
    #[inline]
    fn clone(&self) -> CopyFormat { *self }
}Clone)]
30pub enum CopyFormat {
31    /// The postgresql text format
32    ///
33    /// This format is the default if no format is explicitly set
34    #[default]
35    Text,
36    /// Represents the data as comma separated values (CSV)
37    Csv,
38    /// The postgresql binary format
39    Binary,
40}
41
42impl CopyFormat {
43    fn to_sql_format(self) -> &'static str {
44        match self {
45            CopyFormat::Text => "text",
46            CopyFormat::Csv => "csv",
47            CopyFormat::Binary => "binary",
48        }
49    }
50}
51
52#[derive(#[automatically_derived]
impl ::core::default::Default for CommonOptions {
    #[inline]
    fn default() -> CommonOptions {
        CommonOptions {
            format: ::core::default::Default::default(),
            freeze: ::core::default::Default::default(),
            delimiter: ::core::default::Default::default(),
            null: ::core::default::Default::default(),
            quote: ::core::default::Default::default(),
            escape: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for CommonOptions {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["format", "freeze", "delimiter", "null", "quote", "escape"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.format, &self.freeze, &self.delimiter, &self.null,
                        &self.quote, &&self.escape];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "CommonOptions",
            names, values)
    }
}Debug)]
53struct CommonOptions {
54    format: Option<CopyFormat>,
55    freeze: Option<bool>,
56    delimiter: Option<char>,
57    null: Option<String>,
58    quote: Option<char>,
59    escape: Option<char>,
60}
61
62impl CommonOptions {
63    fn any_set(&self) -> bool {
64        self.format.is_some()
65            || self.freeze.is_some()
66            || self.delimiter.is_some()
67            || self.null.is_some()
68            || self.quote.is_some()
69            || self.escape.is_some()
70    }
71
72    fn walk_ast<'b>(
73        &'b self,
74        mut pass: crate::query_builder::AstPass<'_, 'b, Pg>,
75        comma: &mut &'static str,
76    ) {
77        if let Some(format) = self.format {
78            pass.push_sql(comma);
79            *comma = ", ";
80            pass.push_sql("FORMAT ");
81            pass.push_sql(format.to_sql_format());
82        }
83        if let Some(freeze) = self.freeze {
84            pass.push_sql(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}FREEZE {0}", freeze as u8,
                comma))
    })format!("{comma}FREEZE {}", freeze as u8));
85            *comma = ", ";
86        }
87        if let Some(delimiter) = self.delimiter {
88            pass.push_sql(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}DELIMITER \'{1}\'", comma,
                delimiter))
    })format!("{comma}DELIMITER '{delimiter}'"));
89            *comma = ", ";
90        }
91        if let Some(ref null) = self.null {
92            pass.push_sql(comma);
93            *comma = ", ";
94            pass.push_sql("NULL '");
95            // we cannot use binds here :(
96            pass.push_sql(null);
97            pass.push_sql("'");
98        }
99        if let Some(quote) = self.quote {
100            pass.push_sql(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}QUOTE \'{1}\'", comma, quote))
    })format!("{comma}QUOTE '{quote}'"));
101            *comma = ", ";
102        }
103        if let Some(escape) = self.escape {
104            pass.push_sql(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}ESCAPE \'{1}\'", comma, escape))
    })format!("{comma}ESCAPE '{escape}'"));
105            *comma = ", ";
106        }
107    }
108}
109
110/// A expression that could be used as target/source for `COPY FROM` and `COPY TO` commands
111///
112/// This trait is implemented for any table type and for tuples of columns from the same table
113pub trait CopyTarget {
114    /// The table targeted by the command
115    type Table: Table;
116    /// The sql side type of the target expression
117    type SqlType: SqlType;
118
119    #[doc(hidden)]
120    fn walk_target(pass: crate::query_builder::AstPass<'_, '_, Pg>) -> crate::QueryResult<()>;
121}
122
123impl<T> CopyTarget for T
124where
125    T: Table + StaticQueryFragment,
126    T::SqlType: SqlType,
127    T::AllColumns: ColumnList,
128    T::Component: QueryFragment<Pg>,
129{
130    type Table = Self;
131    type SqlType = T::SqlType;
132
133    fn walk_target(mut pass: crate::query_builder::AstPass<'_, '_, Pg>) -> crate::QueryResult<()> {
134        T::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
135        pass.push_sql("(");
136        T::all_columns().walk_ast(pass.reborrow())?;
137        pass.push_sql(")");
138        Ok(())
139    }
140}
141
142macro_rules! copy_target_for_columns {
143    ($(
144        $Tuple:tt {
145            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
146        }
147    )+) => {
148        $(
149            impl<T, $($ST,)*> CopyTarget for ($($ST,)*)
150            where
151                $($ST: Column<Table = T> + Default,)*
152                ($(<$ST as Expression>::SqlType,)*): SqlType,
153                T: Table + StaticQueryFragment,
154                T::Component: QueryFragment<Pg>,
155                Self: ColumnList,
156            {
157                type Table = T;
158                type SqlType = crate::dsl::SqlTypeOf<Self>;
159
160                fn walk_target(
161                    mut pass: crate::query_builder::AstPass<'_, '_, Pg>,
162                ) -> crate::QueryResult<()> {
163                    T::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
164                    pass.push_sql("(");
165                    <Self as ColumnList>::walk_ast(&($($ST::default(),)*), pass.reborrow())?;
166                    pass.push_sql(")");
167                    Ok(())
168                }
169            }
170        )*
171    }
172}
173
174impl<T, ST, ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8, ST9, ST10, ST11, ST12,
    ST13, ST14, ST15, ST16, ST17, ST18, ST19, ST20, ST21, ST22, ST23, ST24,
    ST25, ST26, ST27, ST28, ST29, ST30, ST31> CopyTarget for
    (ST, ST1, ST2, ST3, ST4, ST5, ST6, ST7, ST8, ST9, ST10, ST11, ST12, ST13,
    ST14, ST15, ST16, ST17, ST18, ST19, ST20, ST21, ST22, ST23, ST24, ST25,
    ST26, ST27, ST28, ST29, ST30, ST31) where ST: Column<Table = T> + Default,
    ST1: Column<Table = T> + Default, ST2: Column<Table = T> + Default,
    ST3: Column<Table = T> + Default, ST4: Column<Table = T> + Default,
    ST5: Column<Table = T> + Default, ST6: Column<Table = T> + Default,
    ST7: Column<Table = T> + Default, ST8: Column<Table = T> + Default,
    ST9: Column<Table = T> + Default, ST10: Column<Table = T> + Default,
    ST11: Column<Table = T> + Default, ST12: Column<Table = T> + Default,
    ST13: Column<Table = T> + Default, ST14: Column<Table = T> + Default,
    ST15: Column<Table = T> + Default, ST16: Column<Table = T> + Default,
    ST17: Column<Table = T> + Default, ST18: Column<Table = T> + Default,
    ST19: Column<Table = T> + Default, ST20: Column<Table = T> + Default,
    ST21: Column<Table = T> + Default, ST22: Column<Table = T> + Default,
    ST23: Column<Table = T> + Default, ST24: Column<Table = T> + Default,
    ST25: Column<Table = T> + Default, ST26: Column<Table = T> + Default,
    ST27: Column<Table = T> + Default, ST28: Column<Table = T> + Default,
    ST29: Column<Table = T> + Default, ST30: Column<Table = T> + Default,
    ST31: Column<Table = T> + Default,
    (<ST as Expression>::SqlType, <ST1 as Expression>::SqlType,
    <ST2 as Expression>::SqlType, <ST3 as Expression>::SqlType,
    <ST4 as Expression>::SqlType, <ST5 as Expression>::SqlType,
    <ST6 as Expression>::SqlType, <ST7 as Expression>::SqlType,
    <ST8 as Expression>::SqlType, <ST9 as Expression>::SqlType,
    <ST10 as Expression>::SqlType, <ST11 as Expression>::SqlType,
    <ST12 as Expression>::SqlType, <ST13 as Expression>::SqlType,
    <ST14 as Expression>::SqlType, <ST15 as Expression>::SqlType,
    <ST16 as Expression>::SqlType, <ST17 as Expression>::SqlType,
    <ST18 as Expression>::SqlType, <ST19 as Expression>::SqlType,
    <ST20 as Expression>::SqlType, <ST21 as Expression>::SqlType,
    <ST22 as Expression>::SqlType, <ST23 as Expression>::SqlType,
    <ST24 as Expression>::SqlType, <ST25 as Expression>::SqlType,
    <ST26 as Expression>::SqlType, <ST27 as Expression>::SqlType,
    <ST28 as Expression>::SqlType, <ST29 as Expression>::SqlType,
    <ST30 as Expression>::SqlType, <ST31 as Expression>::SqlType): SqlType,
    T: Table + StaticQueryFragment, T::Component: QueryFragment<Pg>,
    Self: ColumnList {
    type Table = T;
    type SqlType = crate::dsl::SqlTypeOf<Self>;
    fn walk_target(mut pass: crate::query_builder::AstPass<'_, '_, Pg>)
        -> crate::QueryResult<()> {
        T::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
        pass.push_sql("(");
        <Self as
                    ColumnList>::walk_ast(&(ST::default(), ST1::default(),
                        ST2::default(), ST3::default(), ST4::default(),
                        ST5::default(), ST6::default(), ST7::default(),
                        ST8::default(), ST9::default(), ST10::default(),
                        ST11::default(), ST12::default(), ST13::default(),
                        ST14::default(), ST15::default(), ST16::default(),
                        ST17::default(), ST18::default(), ST19::default(),
                        ST20::default(), ST21::default(), ST22::default(),
                        ST23::default(), ST24::default(), ST25::default(),
                        ST26::default(), ST27::default(), ST28::default(),
                        ST29::default(), ST30::default(), ST31::default()),
                pass.reborrow())?;
        pass.push_sql(")");
        Ok(())
    }
}diesel_derives::__diesel_for_each_tuple!(copy_target_for_columns);