Skip to content

Commit 38a7c6b

Browse files
Removed CSV validation
1 parent 48c476e commit 38a7c6b

File tree

4 files changed

+28
-367
lines changed

4 files changed

+28
-367
lines changed

src/ast/dml.rs

Lines changed: 6 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ use crate::display_utils::{indented_list, Indent, SpaceOrNewline};
3333

3434
use super::{
3535
display_comma_separated, display_separated, helpers::attached_token::AttachedToken,
36-
query::InputFormatClause, Assignment, CopyLegacyCsvOption, CopyLegacyOption, CopyOption,
37-
CopySource, CopyTarget, Expr, FromTable, Ident, InsertAliases, MysqlInsertPriority, ObjectName,
38-
OnInsert, OrderByExpr, Query, SelectItem, Setting, SqliteOnConflict, TableObject,
39-
TableWithJoins, UpdateTableFromKind,
36+
query::InputFormatClause, Assignment, CopyLegacyOption, CopyOption, CopySource, CopyTarget,
37+
Expr, FromTable, Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnInsert, OrderByExpr,
38+
Query, SelectItem, Setting, SqliteOnConflict, TableObject, TableWithJoins, UpdateTableFromKind,
4039
};
4140

4241
/// INSERT statement.
@@ -317,191 +316,6 @@ impl Display for Update {
317316
}
318317
}
319318

320-
/// CSV formatting options extracted from COPY options.
321-
///
322-
/// This struct encapsulates the CSV formatting settings used when parsing
323-
/// or formatting COPY statement data. It extracts relevant options from both
324-
/// modern [`CopyOption`] and legacy [`CopyLegacyOption`] variants.
325-
#[derive(Debug, Clone, PartialEq, Eq)]
326-
pub struct CsvFormatOptions {
327-
/// The field delimiter character (default: tab)
328-
pub(crate) delimiter: char,
329-
/// The quote character used to enclose fields (default: `"`)
330-
pub(crate) quote: char,
331-
/// The escape character (default: `\`)
332-
pub(crate) escape: char,
333-
/// The string representing NULL values (default: `\\N`)
334-
pub(crate) null_symbol: String,
335-
}
336-
337-
impl Default for CsvFormatOptions {
338-
fn default() -> Self {
339-
Self {
340-
delimiter: '\t',
341-
quote: '"',
342-
escape: '\\',
343-
null_symbol: "\\N".to_string(),
344-
}
345-
}
346-
}
347-
348-
impl CsvFormatOptions {
349-
/// Extract CSV format options from CopyOption and CopyLegacyOption lists.
350-
///
351-
/// This method processes both modern and legacy COPY options to determine
352-
/// the CSV formatting settings. Later options in the lists override earlier ones.
353-
///
354-
/// # Arguments
355-
///
356-
/// * `options` - Modern COPY options (PostgreSQL 9.0+)
357-
/// * `legacy_options` - Legacy COPY options (pre-PostgreSQL 9.0)
358-
///
359-
/// # Returns
360-
///
361-
/// A `CsvFormatOptions` instance with the extracted settings, using defaults
362-
/// for any options not specified.
363-
pub(crate) fn from_copy_options(
364-
options: &[CopyOption],
365-
legacy_options: &[CopyLegacyOption],
366-
) -> Self {
367-
let mut csv_options = Self::default();
368-
369-
// Apply options
370-
for option in options {
371-
match option {
372-
CopyOption::Delimiter(c) => {
373-
csv_options.delimiter = *c;
374-
}
375-
CopyOption::Quote(c) => {
376-
csv_options.quote = *c;
377-
}
378-
CopyOption::Escape(c) => {
379-
csv_options.escape = *c;
380-
}
381-
CopyOption::Null(null) => {
382-
csv_options.null_symbol = null.clone();
383-
}
384-
// These options don't affect CSV formatting
385-
CopyOption::Format(_)
386-
| CopyOption::Freeze(_)
387-
| CopyOption::Header(_)
388-
| CopyOption::ForceQuote(_)
389-
| CopyOption::ForceNotNull(_)
390-
| CopyOption::ForceNull(_)
391-
| CopyOption::Encoding(_) => {}
392-
}
393-
}
394-
395-
// Apply legacy options
396-
for option in legacy_options {
397-
match option {
398-
CopyLegacyOption::Delimiter(c) => {
399-
csv_options.delimiter = *c;
400-
}
401-
CopyLegacyOption::Null(null) => {
402-
csv_options.null_symbol = null.clone();
403-
}
404-
CopyLegacyOption::Csv(csv_opts) => {
405-
for csv_option in csv_opts {
406-
match csv_option {
407-
CopyLegacyCsvOption::Quote(c) => {
408-
csv_options.quote = *c;
409-
}
410-
CopyLegacyCsvOption::Escape(c) => {
411-
csv_options.escape = *c;
412-
}
413-
// These CSV options don't affect CSV formatting
414-
CopyLegacyCsvOption::Header
415-
| CopyLegacyCsvOption::ForceQuote(_)
416-
| CopyLegacyCsvOption::ForceNotNull(_) => {}
417-
}
418-
}
419-
}
420-
// These legacy options don't affect CSV formatting
421-
CopyLegacyOption::AcceptAnyDate
422-
| CopyLegacyOption::AcceptInvChars(_)
423-
| CopyLegacyOption::AddQuotes
424-
| CopyLegacyOption::AllowOverwrite
425-
| CopyLegacyOption::Binary
426-
| CopyLegacyOption::BlankAsNull
427-
| CopyLegacyOption::Bzip2
428-
| CopyLegacyOption::CleanPath
429-
| CopyLegacyOption::CompUpdate { .. }
430-
| CopyLegacyOption::DateFormat(_)
431-
| CopyLegacyOption::EmptyAsNull
432-
| CopyLegacyOption::Encrypted { .. }
433-
| CopyLegacyOption::Escape
434-
| CopyLegacyOption::Extension(_)
435-
| CopyLegacyOption::FixedWidth(_)
436-
| CopyLegacyOption::Gzip
437-
| CopyLegacyOption::Header
438-
| CopyLegacyOption::IamRole(_)
439-
| CopyLegacyOption::IgnoreHeader(_)
440-
| CopyLegacyOption::Json
441-
| CopyLegacyOption::Manifest { .. }
442-
| CopyLegacyOption::MaxFileSize(_)
443-
| CopyLegacyOption::Parallel(_)
444-
| CopyLegacyOption::Parquet
445-
| CopyLegacyOption::PartitionBy(_)
446-
| CopyLegacyOption::Region(_)
447-
| CopyLegacyOption::RemoveQuotes
448-
| CopyLegacyOption::RowGroupSize(_)
449-
| CopyLegacyOption::StatUpdate(_)
450-
| CopyLegacyOption::TimeFormat(_)
451-
| CopyLegacyOption::TruncateColumns
452-
| CopyLegacyOption::Zstd => {}
453-
}
454-
}
455-
456-
csv_options
457-
}
458-
459-
/// Format a single CSV field, adding quotes and escaping if necessary.
460-
///
461-
/// This method handles CSV field formatting according to the configured options:
462-
/// - Writes NULL values using the configured `null_symbol`
463-
/// - Adds quotes around fields containing delimiters, quotes, or newlines
464-
/// - Escapes quote characters by doubling them
465-
/// - Escapes escape characters
466-
///
467-
/// # Arguments
468-
///
469-
/// * `f` - The formatter to write to
470-
/// * `field` - The field value to format, or `None` for NULL
471-
///
472-
/// # Returns
473-
///
474-
/// A `fmt::Result` indicating success or failure of the write operation.
475-
fn format_csv_field(&self, f: &mut fmt::Formatter, field: Option<&str>) -> fmt::Result {
476-
let field_value = field.unwrap_or(&self.null_symbol);
477-
478-
// Check if field needs quoting
479-
let needs_quoting = field_value.contains(self.delimiter)
480-
|| field_value.contains(self.quote)
481-
|| field_value.contains('\n')
482-
|| field_value.contains('\r');
483-
484-
if needs_quoting {
485-
write!(f, "{}", self.quote)?;
486-
for ch in field_value.chars() {
487-
if ch == self.quote {
488-
// Escape quote by doubling it
489-
write!(f, "{}{}", self.quote, self.quote)?;
490-
} else if ch == self.escape {
491-
// Escape escape character
492-
write!(f, "{}{}", self.escape, self.escape)?;
493-
} else {
494-
write!(f, "{}", ch)?;
495-
}
496-
}
497-
write!(f, "{}", self.quote)?;
498-
} else {
499-
write!(f, "{}", field_value)?;
500-
}
501-
Ok(())
502-
}
503-
}
504-
505319
/// COPY statement.
506320
///
507321
/// Represents a PostgreSQL COPY statement for bulk data transfer between
@@ -550,7 +364,7 @@ pub struct Copy {
550364
/// CSV data rows for COPY FROM STDIN statements.
551365
/// Each row is a vector of optional strings (None represents NULL).
552366
/// Populated only when copying from STDIN with inline data.
553-
pub values: Vec<Vec<Option<String>>>,
367+
pub values: Option<String>,
554368
}
555369

556370
impl Display for Copy {
@@ -581,24 +395,8 @@ impl Display for Copy {
581395
write!(f, " {}", display_separated(&self.legacy_options, " "))?;
582396
}
583397

584-
if !self.values.is_empty() {
585-
writeln!(f, ";")?;
586-
587-
let csv_options =
588-
CsvFormatOptions::from_copy_options(&self.options, &self.legacy_options);
589-
590-
// Write CSV data
591-
for row in &self.values {
592-
for (idx, column) in row.iter().enumerate() {
593-
if idx > 0 {
594-
write!(f, "{}", csv_options.delimiter)?;
595-
}
596-
csv_options.format_csv_field(f, column.as_deref())?;
597-
}
598-
writeln!(f)?;
599-
}
600-
601-
write!(f, "\\.")?;
398+
if let Some(values) = &self.values {
399+
write!(f, ";{values}\\.")?;
602400
}
603401
Ok(())
604402
}

src/ast/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub use self::ddl::{
7575
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
7676
UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef,
7777
};
78-
pub use self::dml::{Copy, CsvFormatOptions, Delete, Insert, Update};
78+
pub use self::dml::{Copy, Delete, Insert, Update};
7979
pub use self::operator::{BinaryOperator, UnaryOperator};
8080
pub use self::query::{
8181
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,

0 commit comments

Comments
 (0)