1use alloc::borrow::Cow;
2use core::marker::PhantomData;
3
4use byteorder::NetworkEndian;
5use byteorder::WriteBytesExt;
6
7use super::CommonOptions;
8use super::CopyFormat;
9use super::CopyTarget;
10use crate::Connection;
11use crate::Insertable;
12use crate::QueryResult;
13use crate::expression::bound::Bound;
14use crate::insertable::ColumnInsertValue;
15use crate::pg::Pg;
16use crate::pg::PgMetadataLookup;
17use crate::pg::backend::FailedToLookupTypeError;
18use crate::pg::metadata_lookup::PgMetadataCacheKey;
19use crate::query_builder::BatchInsert;
20use crate::query_builder::QueryFragment;
21use crate::query_builder::QueryId;
22use crate::query_builder::ValuesClause;
23use crate::serialize::IsNull;
24use crate::serialize::ToSql;
25use crate::{Column, Table};
26
27#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CopyHeader {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
CopyHeader::Set(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Set",
&__self_0),
CopyHeader::Match =>
::core::fmt::Formatter::write_str(f, "Match"),
}
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for CopyHeader { }Copy, #[automatically_derived]
impl ::core::clone::Clone for CopyHeader {
#[inline]
fn clone(&self) -> CopyHeader {
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone)]
30pub enum CopyHeader {
31 Set(bool),
33 Match,
36}
37
38#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CopyFromOptions {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"CopyFromOptions", "common", &self.common, "default",
&self.default, "header", &&self.header)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for CopyFromOptions {
#[inline]
fn default() -> CopyFromOptions {
CopyFromOptions {
common: ::core::default::Default::default(),
default: ::core::default::Default::default(),
header: ::core::default::Default::default(),
}
}
}Default)]
39pub struct CopyFromOptions {
40 common: CommonOptions,
41 default: Option<String>,
42 header: Option<CopyHeader>,
43}
44
45impl QueryFragment<Pg> for CopyFromOptions {
46 fn walk_ast<'b>(
47 &'b self,
48 mut pass: crate::query_builder::AstPass<'_, 'b, Pg>,
49 ) -> crate::QueryResult<()> {
50 if self.any_set() {
51 let mut comma = "";
52 pass.push_sql(" WITH (");
53 self.common.walk_ast(pass.reborrow(), &mut comma);
54 if let Some(ref default) = self.default {
55 pass.push_sql(comma);
56 comma = ", ";
57 pass.push_sql("DEFAULT '");
58 let default = default.replace('\'', "''");
62 pass.push_sql(&default);
63 pass.push_sql("'");
64 }
65 if let Some(ref header) = self.header {
66 pass.push_sql(comma);
67 pass.push_sql("HEADER ");
70 match header {
71 CopyHeader::Set(true) => pass.push_sql("1"),
72 CopyHeader::Set(false) => pass.push_sql("0"),
73 CopyHeader::Match => pass.push_sql("MATCH"),
74 }
75 }
76
77 pass.push_sql(")");
78 }
79 Ok(())
80 }
81}
82
83impl CopyFromOptions {
84 fn any_set(&self) -> bool {
85 self.common.any_set() || self.default.is_some() || self.header.is_some()
86 }
87}
88
89#[derive(#[automatically_derived]
impl<S: ::core::fmt::Debug, F: ::core::fmt::Debug> ::core::fmt::Debug for
CopyFrom<S, F> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "CopyFrom",
"options", &self.options, "copy_callback", &self.copy_callback,
"p", &&self.p)
}
}Debug)]
90pub struct CopyFrom<S, F> {
91 options: CopyFromOptions,
92 copy_callback: F,
93 p: PhantomData<S>,
94}
95
96pub(crate) struct InternalCopyFromQuery<S, T> {
97 pub(crate) target: S,
98 p: PhantomData<T>,
99}
100
101#[cfg(feature = "postgres")]
102impl<S, T> InternalCopyFromQuery<S, T> {
103 pub(crate) fn new(target: S) -> Self {
104 Self {
105 target,
106 p: PhantomData,
107 }
108 }
109}
110
111impl<S, T> QueryId for InternalCopyFromQuery<S, T>
112where
113 S: CopyFromExpression<T>,
114{
115 const HAS_STATIC_QUERY_ID: bool = false;
116 type QueryId = ();
117}
118
119impl<S, T> QueryFragment<Pg> for InternalCopyFromQuery<S, T>
120where
121 S: CopyFromExpression<T>,
122{
123 fn walk_ast<'b>(
124 &'b self,
125 mut pass: crate::query_builder::AstPass<'_, 'b, Pg>,
126 ) -> crate::QueryResult<()> {
127 pass.unsafe_to_cache_prepared();
128 pass.push_sql("COPY ");
129 self.target.walk_target(pass.reborrow())?;
130 pass.push_sql(" FROM STDIN");
131 self.target.options().walk_ast(pass.reborrow())?;
132 Ok(())
133 }
134}
135
136pub trait CopyFromExpression<T> {
137 type Error: From<crate::result::Error> + core::error::Error;
138
139 fn callback(&mut self, copy: &mut impl std::io::Write) -> Result<(), Self::Error>;
140
141 fn walk_target<'b>(
142 &'b self,
143 pass: crate::query_builder::AstPass<'_, 'b, Pg>,
144 ) -> crate::QueryResult<()>;
145
146 fn options(&self) -> &CopyFromOptions;
147}
148
149impl<S, F, E> CopyFromExpression<S::Table> for CopyFrom<S, F>
150where
151 E: From<crate::result::Error> + core::error::Error,
152 S: CopyTarget,
153 F: Fn(&mut dyn std::io::Write) -> Result<(), E>,
154{
155 type Error = E;
156
157 fn callback(&mut self, copy: &mut impl std::io::Write) -> Result<(), Self::Error> {
158 (self.copy_callback)(copy)
159 }
160
161 fn options(&self) -> &CopyFromOptions {
162 &self.options
163 }
164
165 fn walk_target<'b>(
166 &'b self,
167 pass: crate::query_builder::AstPass<'_, 'b, Pg>,
168 ) -> crate::QueryResult<()> {
169 S::walk_target(pass)
170 }
171}
172
173struct Dummy;
174
175impl PgMetadataLookup for Dummy {
176 fn lookup_type(&mut self, type_name: &str, schema: Option<&str>) -> crate::pg::PgTypeMetadata {
177 let cache_key = PgMetadataCacheKey::new(
178 schema.map(Into::into).map(Cow::Owned),
179 Cow::Owned(type_name.into()),
180 );
181 crate::pg::PgTypeMetadata(Err(FailedToLookupTypeError::new_internal(cache_key)))
182 }
183}
184
185trait CopyFromInsertableHelper {
186 type Target: CopyTarget;
187 const COLUMN_COUNT: i16;
188
189 fn write_to_buffer(&self, idx: i16, out: &mut Vec<u8>) -> QueryResult<IsNull>;
190}
191
192macro_rules! impl_copy_from_insertable_helper_for_values_clause {
193 ($(
194 $Tuple:tt {
195 $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
196 }
197 )+) => {
198 $(
199 impl<__T, $($ST,)* $($T,)* $($TT,)*> CopyFromInsertableHelper for ValuesClause<
200 ($(ColumnInsertValue<$ST, Bound<$T, $TT>>,)*),
201 __T>
202 where
203 __T: Table,
204 $($ST: Column<Table = __T>,)*
205 ($($ST,)*): CopyTarget,
206 $($TT: ToSql<$T, Pg>,)*
207 {
208 type Target = ($($ST,)*);
209
210 #[allow(clippy::cast_possible_truncation)]
213 const COLUMN_COUNT: i16 = $Tuple as i16;
214
215 fn write_to_buffer(&self, idx: i16, out: &mut Vec<u8>) -> QueryResult<IsNull> {
216 use crate::query_builder::ByteWrapper;
217 use crate::serialize::Output;
218
219 let values = &self.values;
220 match idx {
221 $($idx =>{
222 let item = &values.$idx.expr.item;
223 let is_null = ToSql::<$T, Pg>::to_sql(
224 item,
225 &mut Output::new( ByteWrapper(out), &mut Dummy as _)
226 ).map_err(crate::result::Error::SerializationError)?;
227 return Ok(is_null);
228 })*
229 _ => unreachable!(),
230 }
231 }
232 }
233
234 impl<'a, __T, $($ST,)* $($T,)* $($TT,)*> CopyFromInsertableHelper for ValuesClause<
235 ($(ColumnInsertValue<$ST, &'a Bound<$T, $TT>>,)*),
236 __T>
237 where
238 __T: Table,
239 $($ST: Column<Table = __T>,)*
240 ($($ST,)*): CopyTarget,
241 $($TT: ToSql<$T, Pg>,)*
242 {
243 type Target = ($($ST,)*);
244
245 #[allow(clippy::cast_possible_truncation)]
248 const COLUMN_COUNT: i16 = $Tuple as i16;
249
250 fn write_to_buffer(&self, idx: i16, out: &mut Vec<u8>) -> QueryResult<IsNull> {
251 use crate::query_builder::ByteWrapper;
252 use crate::serialize::Output;
253
254 let values = &self.values;
255 match idx {
256 $($idx =>{
257 let item = &values.$idx.expr.item;
258 let is_null = ToSql::<$T, Pg>::to_sql(
259 item,
260 &mut Output::new( ByteWrapper(out), &mut Dummy as _)
261 ).map_err(crate::result::Error::SerializationError)?;
262 return Ok(is_null);
263 })*
264 _ => unreachable!(),
265 }
266 }
267 }
268 )*
269 }
270}
271
272impl<__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, T, T1, T2, T3, T4, T5, T6, T7,
T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22,
T23, T24, T25, T26, T27, T28, T29, T30, T31, TT, TT1, TT2, TT3, TT4, TT5,
TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16, TT17, TT18,
TT19, TT20, TT21, TT22, TT23, TT24, TT25, TT26, TT27, TT28, TT29, TT30,
TT31> CopyFromInsertableHelper for
ValuesClause<(ColumnInsertValue<ST, Bound<T, TT>>,
ColumnInsertValue<ST1, Bound<T1, TT1>>,
ColumnInsertValue<ST2, Bound<T2, TT2>>,
ColumnInsertValue<ST3, Bound<T3, TT3>>,
ColumnInsertValue<ST4, Bound<T4, TT4>>,
ColumnInsertValue<ST5, Bound<T5, TT5>>,
ColumnInsertValue<ST6, Bound<T6, TT6>>,
ColumnInsertValue<ST7, Bound<T7, TT7>>,
ColumnInsertValue<ST8, Bound<T8, TT8>>,
ColumnInsertValue<ST9, Bound<T9, TT9>>,
ColumnInsertValue<ST10, Bound<T10, TT10>>,
ColumnInsertValue<ST11, Bound<T11, TT11>>,
ColumnInsertValue<ST12, Bound<T12, TT12>>,
ColumnInsertValue<ST13, Bound<T13, TT13>>,
ColumnInsertValue<ST14, Bound<T14, TT14>>,
ColumnInsertValue<ST15, Bound<T15, TT15>>,
ColumnInsertValue<ST16, Bound<T16, TT16>>,
ColumnInsertValue<ST17, Bound<T17, TT17>>,
ColumnInsertValue<ST18, Bound<T18, TT18>>,
ColumnInsertValue<ST19, Bound<T19, TT19>>,
ColumnInsertValue<ST20, Bound<T20, TT20>>,
ColumnInsertValue<ST21, Bound<T21, TT21>>,
ColumnInsertValue<ST22, Bound<T22, TT22>>,
ColumnInsertValue<ST23, Bound<T23, TT23>>,
ColumnInsertValue<ST24, Bound<T24, TT24>>,
ColumnInsertValue<ST25, Bound<T25, TT25>>,
ColumnInsertValue<ST26, Bound<T26, TT26>>,
ColumnInsertValue<ST27, Bound<T27, TT27>>,
ColumnInsertValue<ST28, Bound<T28, TT28>>,
ColumnInsertValue<ST29, Bound<T29, TT29>>,
ColumnInsertValue<ST30, Bound<T30, TT30>>,
ColumnInsertValue<ST31, Bound<T31, TT31>>), __T> where __T: Table,
ST: Column<Table = __T>, ST1: Column<Table = __T>,
ST2: Column<Table = __T>, ST3: Column<Table = __T>,
ST4: Column<Table = __T>, ST5: Column<Table = __T>,
ST6: Column<Table = __T>, ST7: Column<Table = __T>,
ST8: Column<Table = __T>, ST9: Column<Table = __T>,
ST10: Column<Table = __T>, ST11: Column<Table = __T>,
ST12: Column<Table = __T>, ST13: Column<Table = __T>,
ST14: Column<Table = __T>, ST15: Column<Table = __T>,
ST16: Column<Table = __T>, ST17: Column<Table = __T>,
ST18: Column<Table = __T>, ST19: Column<Table = __T>,
ST20: Column<Table = __T>, ST21: Column<Table = __T>,
ST22: Column<Table = __T>, ST23: Column<Table = __T>,
ST24: Column<Table = __T>, ST25: Column<Table = __T>,
ST26: Column<Table = __T>, ST27: Column<Table = __T>,
ST28: Column<Table = __T>, ST29: Column<Table = __T>,
ST30: Column<Table = __T>, ST31: Column<Table = __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, TT: ToSql<T, Pg>,
TT1: ToSql<T1, Pg>, TT2: ToSql<T2, Pg>, TT3: ToSql<T3, Pg>,
TT4: ToSql<T4, Pg>, TT5: ToSql<T5, Pg>, TT6: ToSql<T6, Pg>,
TT7: ToSql<T7, Pg>, TT8: ToSql<T8, Pg>, TT9: ToSql<T9, Pg>,
TT10: ToSql<T10, Pg>, TT11: ToSql<T11, Pg>, TT12: ToSql<T12, Pg>,
TT13: ToSql<T13, Pg>, TT14: ToSql<T14, Pg>, TT15: ToSql<T15, Pg>,
TT16: ToSql<T16, Pg>, TT17: ToSql<T17, Pg>, TT18: ToSql<T18, Pg>,
TT19: ToSql<T19, Pg>, TT20: ToSql<T20, Pg>, TT21: ToSql<T21, Pg>,
TT22: ToSql<T22, Pg>, TT23: ToSql<T23, Pg>, TT24: ToSql<T24, Pg>,
TT25: ToSql<T25, Pg>, TT26: ToSql<T26, Pg>, TT27: ToSql<T27, Pg>,
TT28: ToSql<T28, Pg>, TT29: ToSql<T29, Pg>, TT30: ToSql<T30, Pg>,
TT31: ToSql<T31, Pg> {
type Target =
(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);
#[allow(clippy :: cast_possible_truncation)]
const COLUMN_COUNT: i16 = 32i32 as i16;
fn write_to_buffer(&self, idx: i16, out: &mut Vec<u8>)
-> QueryResult<IsNull> {
use crate::query_builder::ByteWrapper;
use crate::serialize::Output;
let values = &self.values;
match idx {
0 => {
let item = &values.0.expr.item;
let is_null =
ToSql::<T,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
1 => {
let item = &values.1.expr.item;
let is_null =
ToSql::<T1,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
2 => {
let item = &values.2.expr.item;
let is_null =
ToSql::<T2,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
3 => {
let item = &values.3.expr.item;
let is_null =
ToSql::<T3,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
4 => {
let item = &values.4.expr.item;
let is_null =
ToSql::<T4,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
5 => {
let item = &values.5.expr.item;
let is_null =
ToSql::<T5,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
6 => {
let item = &values.6.expr.item;
let is_null =
ToSql::<T6,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
7 => {
let item = &values.7.expr.item;
let is_null =
ToSql::<T7,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
8 => {
let item = &values.8.expr.item;
let is_null =
ToSql::<T8,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
9 => {
let item = &values.9.expr.item;
let is_null =
ToSql::<T9,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
10 => {
let item = &values.10.expr.item;
let is_null =
ToSql::<T10,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
11 => {
let item = &values.11.expr.item;
let is_null =
ToSql::<T11,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
12 => {
let item = &values.12.expr.item;
let is_null =
ToSql::<T12,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
13 => {
let item = &values.13.expr.item;
let is_null =
ToSql::<T13,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
14 => {
let item = &values.14.expr.item;
let is_null =
ToSql::<T14,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
15 => {
let item = &values.15.expr.item;
let is_null =
ToSql::<T15,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
16 => {
let item = &values.16.expr.item;
let is_null =
ToSql::<T16,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
17 => {
let item = &values.17.expr.item;
let is_null =
ToSql::<T17,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
18 => {
let item = &values.18.expr.item;
let is_null =
ToSql::<T18,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
19 => {
let item = &values.19.expr.item;
let is_null =
ToSql::<T19,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
20 => {
let item = &values.20.expr.item;
let is_null =
ToSql::<T20,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
21 => {
let item = &values.21.expr.item;
let is_null =
ToSql::<T21,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
22 => {
let item = &values.22.expr.item;
let is_null =
ToSql::<T22,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
23 => {
let item = &values.23.expr.item;
let is_null =
ToSql::<T23,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
24 => {
let item = &values.24.expr.item;
let is_null =
ToSql::<T24,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
25 => {
let item = &values.25.expr.item;
let is_null =
ToSql::<T25,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
26 => {
let item = &values.26.expr.item;
let is_null =
ToSql::<T26,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
27 => {
let item = &values.27.expr.item;
let is_null =
ToSql::<T27,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
28 => {
let item = &values.28.expr.item;
let is_null =
ToSql::<T28,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
29 => {
let item = &values.29.expr.item;
let is_null =
ToSql::<T29,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
30 => {
let item = &values.30.expr.item;
let is_null =
ToSql::<T30,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
31 => {
let item = &values.31.expr.item;
let is_null =
ToSql::<T31,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
}
impl<'a, __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, T, T1, T2, T3, T4, T5, T6,
T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, TT, TT1, TT2, TT3, TT4,
TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16, TT17,
TT18, TT19, TT20, TT21, TT22, TT23, TT24, TT25, TT26, TT27, TT28, TT29,
TT30, TT31> CopyFromInsertableHelper for
ValuesClause<(ColumnInsertValue<ST, &'a Bound<T, TT>>,
ColumnInsertValue<ST1, &'a Bound<T1, TT1>>,
ColumnInsertValue<ST2, &'a Bound<T2, TT2>>,
ColumnInsertValue<ST3, &'a Bound<T3, TT3>>,
ColumnInsertValue<ST4, &'a Bound<T4, TT4>>,
ColumnInsertValue<ST5, &'a Bound<T5, TT5>>,
ColumnInsertValue<ST6, &'a Bound<T6, TT6>>,
ColumnInsertValue<ST7, &'a Bound<T7, TT7>>,
ColumnInsertValue<ST8, &'a Bound<T8, TT8>>,
ColumnInsertValue<ST9, &'a Bound<T9, TT9>>,
ColumnInsertValue<ST10, &'a Bound<T10, TT10>>,
ColumnInsertValue<ST11, &'a Bound<T11, TT11>>,
ColumnInsertValue<ST12, &'a Bound<T12, TT12>>,
ColumnInsertValue<ST13, &'a Bound<T13, TT13>>,
ColumnInsertValue<ST14, &'a Bound<T14, TT14>>,
ColumnInsertValue<ST15, &'a Bound<T15, TT15>>,
ColumnInsertValue<ST16, &'a Bound<T16, TT16>>,
ColumnInsertValue<ST17, &'a Bound<T17, TT17>>,
ColumnInsertValue<ST18, &'a Bound<T18, TT18>>,
ColumnInsertValue<ST19, &'a Bound<T19, TT19>>,
ColumnInsertValue<ST20, &'a Bound<T20, TT20>>,
ColumnInsertValue<ST21, &'a Bound<T21, TT21>>,
ColumnInsertValue<ST22, &'a Bound<T22, TT22>>,
ColumnInsertValue<ST23, &'a Bound<T23, TT23>>,
ColumnInsertValue<ST24, &'a Bound<T24, TT24>>,
ColumnInsertValue<ST25, &'a Bound<T25, TT25>>,
ColumnInsertValue<ST26, &'a Bound<T26, TT26>>,
ColumnInsertValue<ST27, &'a Bound<T27, TT27>>,
ColumnInsertValue<ST28, &'a Bound<T28, TT28>>,
ColumnInsertValue<ST29, &'a Bound<T29, TT29>>,
ColumnInsertValue<ST30, &'a Bound<T30, TT30>>,
ColumnInsertValue<ST31, &'a Bound<T31, TT31>>), __T> where __T: Table,
ST: Column<Table = __T>, ST1: Column<Table = __T>,
ST2: Column<Table = __T>, ST3: Column<Table = __T>,
ST4: Column<Table = __T>, ST5: Column<Table = __T>,
ST6: Column<Table = __T>, ST7: Column<Table = __T>,
ST8: Column<Table = __T>, ST9: Column<Table = __T>,
ST10: Column<Table = __T>, ST11: Column<Table = __T>,
ST12: Column<Table = __T>, ST13: Column<Table = __T>,
ST14: Column<Table = __T>, ST15: Column<Table = __T>,
ST16: Column<Table = __T>, ST17: Column<Table = __T>,
ST18: Column<Table = __T>, ST19: Column<Table = __T>,
ST20: Column<Table = __T>, ST21: Column<Table = __T>,
ST22: Column<Table = __T>, ST23: Column<Table = __T>,
ST24: Column<Table = __T>, ST25: Column<Table = __T>,
ST26: Column<Table = __T>, ST27: Column<Table = __T>,
ST28: Column<Table = __T>, ST29: Column<Table = __T>,
ST30: Column<Table = __T>, ST31: Column<Table = __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, TT: ToSql<T, Pg>,
TT1: ToSql<T1, Pg>, TT2: ToSql<T2, Pg>, TT3: ToSql<T3, Pg>,
TT4: ToSql<T4, Pg>, TT5: ToSql<T5, Pg>, TT6: ToSql<T6, Pg>,
TT7: ToSql<T7, Pg>, TT8: ToSql<T8, Pg>, TT9: ToSql<T9, Pg>,
TT10: ToSql<T10, Pg>, TT11: ToSql<T11, Pg>, TT12: ToSql<T12, Pg>,
TT13: ToSql<T13, Pg>, TT14: ToSql<T14, Pg>, TT15: ToSql<T15, Pg>,
TT16: ToSql<T16, Pg>, TT17: ToSql<T17, Pg>, TT18: ToSql<T18, Pg>,
TT19: ToSql<T19, Pg>, TT20: ToSql<T20, Pg>, TT21: ToSql<T21, Pg>,
TT22: ToSql<T22, Pg>, TT23: ToSql<T23, Pg>, TT24: ToSql<T24, Pg>,
TT25: ToSql<T25, Pg>, TT26: ToSql<T26, Pg>, TT27: ToSql<T27, Pg>,
TT28: ToSql<T28, Pg>, TT29: ToSql<T29, Pg>, TT30: ToSql<T30, Pg>,
TT31: ToSql<T31, Pg> {
type Target =
(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);
#[allow(clippy :: cast_possible_truncation)]
const COLUMN_COUNT: i16 = 32i32 as i16;
fn write_to_buffer(&self, idx: i16, out: &mut Vec<u8>)
-> QueryResult<IsNull> {
use crate::query_builder::ByteWrapper;
use crate::serialize::Output;
let values = &self.values;
match idx {
0 => {
let item = &values.0.expr.item;
let is_null =
ToSql::<T,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
1 => {
let item = &values.1.expr.item;
let is_null =
ToSql::<T1,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
2 => {
let item = &values.2.expr.item;
let is_null =
ToSql::<T2,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
3 => {
let item = &values.3.expr.item;
let is_null =
ToSql::<T3,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
4 => {
let item = &values.4.expr.item;
let is_null =
ToSql::<T4,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
5 => {
let item = &values.5.expr.item;
let is_null =
ToSql::<T5,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
6 => {
let item = &values.6.expr.item;
let is_null =
ToSql::<T6,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
7 => {
let item = &values.7.expr.item;
let is_null =
ToSql::<T7,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
8 => {
let item = &values.8.expr.item;
let is_null =
ToSql::<T8,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
9 => {
let item = &values.9.expr.item;
let is_null =
ToSql::<T9,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
10 => {
let item = &values.10.expr.item;
let is_null =
ToSql::<T10,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
11 => {
let item = &values.11.expr.item;
let is_null =
ToSql::<T11,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
12 => {
let item = &values.12.expr.item;
let is_null =
ToSql::<T12,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
13 => {
let item = &values.13.expr.item;
let is_null =
ToSql::<T13,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
14 => {
let item = &values.14.expr.item;
let is_null =
ToSql::<T14,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
15 => {
let item = &values.15.expr.item;
let is_null =
ToSql::<T15,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
16 => {
let item = &values.16.expr.item;
let is_null =
ToSql::<T16,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
17 => {
let item = &values.17.expr.item;
let is_null =
ToSql::<T17,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
18 => {
let item = &values.18.expr.item;
let is_null =
ToSql::<T18,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
19 => {
let item = &values.19.expr.item;
let is_null =
ToSql::<T19,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
20 => {
let item = &values.20.expr.item;
let is_null =
ToSql::<T20,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
21 => {
let item = &values.21.expr.item;
let is_null =
ToSql::<T21,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
22 => {
let item = &values.22.expr.item;
let is_null =
ToSql::<T22,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
23 => {
let item = &values.23.expr.item;
let is_null =
ToSql::<T23,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
24 => {
let item = &values.24.expr.item;
let is_null =
ToSql::<T24,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
25 => {
let item = &values.25.expr.item;
let is_null =
ToSql::<T25,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
26 => {
let item = &values.26.expr.item;
let is_null =
ToSql::<T26,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
27 => {
let item = &values.27.expr.item;
let is_null =
ToSql::<T27,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
28 => {
let item = &values.28.expr.item;
let is_null =
ToSql::<T28,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
29 => {
let item = &values.29.expr.item;
let is_null =
ToSql::<T29,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
30 => {
let item = &values.30.expr.item;
let is_null =
ToSql::<T30,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
31 => {
let item = &values.31.expr.item;
let is_null =
ToSql::<T31,
Pg>::to_sql(item,
&mut Output::new(ByteWrapper(out),
&mut Dummy as
_)).map_err(crate::result::Error::SerializationError)?;
return Ok(is_null);
}
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
}diesel_derives::__diesel_for_each_tuple!(impl_copy_from_insertable_helper_for_values_clause);
273
274#[derive(#[automatically_derived]
impl<I: ::core::fmt::Debug> ::core::fmt::Debug for InsertableWrapper<I> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InsertableWrapper", &&self.0)
}
}Debug)]
275pub struct InsertableWrapper<I>(Option<I>);
276
277impl<I, T, V, QId, const STATIC_QUERY_ID: bool> CopyFromExpression<T> for InsertableWrapper<I>
278where
279 I: Insertable<T, Values = BatchInsert<Vec<V>, T, QId, STATIC_QUERY_ID>>,
280 V: CopyFromInsertableHelper,
281{
282 type Error = crate::result::Error;
283
284 fn callback(&mut self, copy: &mut impl std::io::Write) -> Result<(), Self::Error> {
285 let io_result_mapper = |e| crate::result::Error::DeserializationError(Box::new(e));
286 copy.write_all(&super::COPY_MAGIC_HEADER)
293 .map_err(io_result_mapper)?;
294 copy.write_i32::<NetworkEndian>(0)
295 .map_err(io_result_mapper)?;
296 copy.write_i32::<NetworkEndian>(0)
297 .map_err(io_result_mapper)?;
298 let mut buffer = Vec::<u8>::new();
303 let values = self
304 .0
305 .take()
306 .expect("We only call this callback once")
307 .values();
308 for i in values.values {
309 buffer
311 .write_i16::<NetworkEndian>(V::COLUMN_COUNT)
312 .map_err(io_result_mapper)?;
313 for idx in 0..V::COLUMN_COUNT {
314 buffer
316 .write_i32::<NetworkEndian>(-1)
317 .map_err(io_result_mapper)?;
318 let len_before = buffer.len();
319 let is_null = i.write_to_buffer(idx, &mut buffer)?;
320 if is_null == IsNull::No {
321 let len_after = buffer.len();
323 let diff = (len_after - len_before)
324 .try_into()
325 .map_err(|e| crate::result::Error::SerializationError(Box::new(e)))?;
326 let bytes = i32::to_be_bytes(diff);
327 for (b, t) in bytes.into_iter().zip(&mut buffer[len_before - 4..]) {
328 *t = b;
329 }
330 }
331 }
332 copy.write_all(&buffer).map_err(io_result_mapper)?;
333 buffer.clear();
334 }
335 copy.write_i16::<NetworkEndian>(-1)
337 .map_err(io_result_mapper)?;
338 Ok(())
339 }
340
341 fn options(&self) -> &CopyFromOptions {
342 &CopyFromOptions {
343 common: CommonOptions {
344 format: Some(CopyFormat::Binary),
345 freeze: None,
346 delimiter: None,
347 null: None,
348 quote: None,
349 escape: None,
350 },
351 default: None,
352 header: None,
353 }
354 }
355
356 fn walk_target<'b>(
357 &'b self,
358 pass: crate::query_builder::AstPass<'_, 'b, Pg>,
359 ) -> crate::QueryResult<()> {
360 <V as CopyFromInsertableHelper>::Target::walk_target(pass)
361 }
362}
363
364#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, Action: ::core::fmt::Debug> ::core::fmt::Debug for
CopyFromQuery<T, Action> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "CopyFromQuery",
"table", &self.table, "action", &&self.action)
}
}Debug)]
375#[must_use = "`COPY FROM` statements are only executed when calling `.execute()`."]
376#[cfg(feature = "postgres_backend")]
377pub struct CopyFromQuery<T, Action> {
378 table: T,
379 action: Action,
380}
381
382impl<T> CopyFromQuery<T, NotSet>
383where
384 T: Table,
385{
386 #[allow(clippy::wrong_self_convention)] pub fn from_raw_data<F, C, E>(self, _target: C, action: F) -> CopyFromQuery<T, CopyFrom<C, F>>
393 where
394 C: CopyTarget<Table = T>,
395 F: Fn(&mut dyn std::io::Write) -> Result<(), E>,
396 {
397 CopyFromQuery {
398 table: self.table,
399 action: CopyFrom {
400 p: PhantomData,
401 options: Default::default(),
402 copy_callback: action,
403 },
404 }
405 }
406
407 #[allow(clippy::wrong_self_convention)] pub fn from_insertable<I>(self, insertable: I) -> CopyFromQuery<T, InsertableWrapper<I>>
418 where
419 InsertableWrapper<I>: CopyFromExpression<T>,
420 {
421 CopyFromQuery {
422 table: self.table,
423 action: InsertableWrapper(Some(insertable)),
424 }
425 }
426}
427
428impl<T, C, F> CopyFromQuery<T, CopyFrom<C, F>> {
429 pub fn with_format(mut self, format: CopyFormat) -> Self {
434 self.action.options.common.format = Some(format);
435 self
436 }
437
438 pub fn with_freeze(mut self, freeze: bool) -> Self {
443 self.action.options.common.freeze = Some(freeze);
444 self
445 }
446
447 pub fn with_delimiter(mut self, delimiter: char) -> Self {
452 self.action.options.common.delimiter = Some(delimiter);
453 self
454 }
455
456 pub fn with_null(mut self, null: impl Into<String>) -> Self {
462 self.action.options.common.null = Some(null.into());
463 self
464 }
465
466 pub fn with_quote(mut self, quote: char) -> Self {
471 self.action.options.common.quote = Some(quote);
472 self
473 }
474
475 pub fn with_escape(mut self, escape: char) -> Self {
480 self.action.options.common.escape = Some(escape);
481 self
482 }
483
484 pub fn with_default(mut self, default: impl Into<String>) -> Self {
493 self.action.options.default = Some(default.into());
494 self
495 }
496
497 pub fn with_header(mut self, header: CopyHeader) -> Self {
502 self.action.options.header = Some(header);
503 self
504 }
505}
506
507pub trait ExecuteCopyFromDsl<C>
512where
513 C: Connection<Backend = Pg>,
514{
515 type Error: core::error::Error;
517
518 fn execute(self, conn: &mut C) -> Result<usize, Self::Error>;
520}
521
522#[cfg(feature = "postgres")]
523impl<T, A> ExecuteCopyFromDsl<crate::PgConnection> for CopyFromQuery<T, A>
524where
525 A: CopyFromExpression<T>,
526{
527 type Error = A::Error;
528
529 fn execute(self, conn: &mut crate::PgConnection) -> Result<usize, A::Error> {
530 conn.copy_from::<A, T>(self.action)
531 }
532}
533
534#[cfg(feature = "r2d2")]
535impl<T, A, C> ExecuteCopyFromDsl<crate::r2d2::PooledConnection<crate::r2d2::ConnectionManager<C>>>
536 for CopyFromQuery<T, A>
537where
538 A: CopyFromExpression<T>,
539 C: crate::r2d2::R2D2Connection<Backend = Pg> + 'static,
540 Self: ExecuteCopyFromDsl<C>,
541{
542 type Error = <Self as ExecuteCopyFromDsl<C>>::Error;
543
544 fn execute(
545 self,
546 conn: &mut crate::r2d2::PooledConnection<crate::r2d2::ConnectionManager<C>>,
547 ) -> Result<usize, Self::Error> {
548 self.execute(&mut **conn)
549 }
550}
551
552#[derive(#[automatically_derived]
impl ::core::fmt::Debug for NotSet {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "NotSet")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for NotSet {
#[inline]
fn clone(&self) -> NotSet { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for NotSet { }Copy)]
553pub struct NotSet;
554
555#[cfg(feature = "postgres_backend")]
655pub fn copy_from<T>(table: T) -> CopyFromQuery<T, NotSet>
656where
657 T: Table,
658{
659 CopyFromQuery {
660 table,
661 action: NotSet,
662 }
663}