github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/copy.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode"
    15  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror"
    16  )
    17  
    18  // CopyFrom represents a COPY FROM statement.
    19  type CopyFrom struct {
    20  	Table   TableName
    21  	Columns NameList
    22  	Stdin   bool
    23  	Options CopyOptions
    24  }
    25  
    26  // CopyTo represents a COPY TO statement.
    27  type CopyTo struct {
    28  	Table     TableName
    29  	Columns   NameList
    30  	Statement Statement
    31  	Options   CopyOptions
    32  }
    33  
    34  // Format implements the NodeFormatter interface.
    35  func (node *CopyTo) Format(ctx *FmtCtx) {
    36  	ctx.WriteString("COPY ")
    37  	if node.Statement != nil {
    38  		ctx.WriteString("(")
    39  		ctx.FormatNode(node.Statement)
    40  		ctx.WriteString(")")
    41  	} else {
    42  		ctx.FormatNode(&node.Table)
    43  		if len(node.Columns) > 0 {
    44  			ctx.WriteString(" (")
    45  			ctx.FormatNode(&node.Columns)
    46  			ctx.WriteString(")")
    47  		}
    48  	}
    49  	ctx.WriteString(" TO STDOUT")
    50  	if !node.Options.IsDefault() {
    51  		ctx.WriteString(" WITH ")
    52  		ctx.FormatNode(&node.Options)
    53  	}
    54  }
    55  
    56  // CopyOptions describes options for COPY execution.
    57  type CopyOptions struct {
    58  	Destination Expr
    59  	CopyFormat  CopyFormat
    60  	Delimiter   Expr
    61  	Null        Expr
    62  	Escape      *StrVal
    63  	Header      bool
    64  	Quote       *StrVal
    65  
    66  	// Additional flags are needed to keep track of whether explicit default
    67  	// values were already set.
    68  	HasFormat bool
    69  	HasHeader bool
    70  }
    71  
    72  var _ NodeFormatter = &CopyOptions{}
    73  
    74  // Format implements the NodeFormatter interface.
    75  func (node *CopyFrom) Format(ctx *FmtCtx) {
    76  	ctx.WriteString("COPY ")
    77  	ctx.FormatNode(&node.Table)
    78  	if len(node.Columns) > 0 {
    79  		ctx.WriteString(" (")
    80  		ctx.FormatNode(&node.Columns)
    81  		ctx.WriteString(")")
    82  	}
    83  	ctx.WriteString(" FROM ")
    84  	if node.Stdin {
    85  		ctx.WriteString("STDIN")
    86  	}
    87  	if !node.Options.IsDefault() {
    88  		ctx.WriteString(" WITH ")
    89  		ctx.FormatNode(&node.Options)
    90  	}
    91  }
    92  
    93  // Format implements the NodeFormatter interface
    94  func (o *CopyOptions) Format(ctx *FmtCtx) {
    95  	var addSep bool
    96  	maybeAddSep := func() {
    97  		if addSep {
    98  			ctx.WriteString(", ")
    99  		}
   100  		addSep = true
   101  	}
   102  	ctx.WriteString("(")
   103  	if o.HasFormat {
   104  		maybeAddSep()
   105  		switch o.CopyFormat {
   106  		case CopyFormatBinary:
   107  			ctx.WriteString("FORMAT BINARY")
   108  		case CopyFormatCSV:
   109  			ctx.WriteString("FORMAT CSV")
   110  		case CopyFormatText:
   111  			ctx.WriteString("FORMAT TEXT")
   112  		}
   113  	}
   114  	if o.Delimiter != nil {
   115  		maybeAddSep()
   116  		ctx.WriteString("DELIMITER ")
   117  		ctx.FormatNode(o.Delimiter)
   118  		addSep = true
   119  	}
   120  	if o.Null != nil {
   121  		maybeAddSep()
   122  		ctx.WriteString("NULL ")
   123  		ctx.FormatNode(o.Null)
   124  		addSep = true
   125  	}
   126  	if o.Destination != nil {
   127  		maybeAddSep()
   128  		// Lowercase because that's what has historically been produced
   129  		// by copy_file_upload.go, so this will provide backward
   130  		// compatibility with older servers.
   131  		ctx.WriteString("DESTINATION ")
   132  		ctx.FormatNode(o.Destination)
   133  		addSep = true
   134  	}
   135  	if o.Escape != nil {
   136  		maybeAddSep()
   137  		ctx.WriteString("ESCAPE ")
   138  		ctx.FormatNode(o.Escape)
   139  	}
   140  	if o.HasHeader {
   141  		maybeAddSep()
   142  		ctx.WriteString("HEADER ")
   143  		if o.Header {
   144  			ctx.WriteString("true")
   145  		} else {
   146  			ctx.WriteString("false")
   147  		}
   148  	}
   149  	if o.Quote != nil {
   150  		maybeAddSep()
   151  		ctx.WriteString("QUOTE ")
   152  		ctx.FormatNode(o.Quote)
   153  	}
   154  	ctx.WriteString(")")
   155  }
   156  
   157  // IsDefault returns true if this struct has default value.
   158  func (o CopyOptions) IsDefault() bool {
   159  	return o == CopyOptions{}
   160  }
   161  
   162  // CombineWith merges other options into this struct. An error is returned if
   163  // the same option merged multiple times.
   164  func (o *CopyOptions) CombineWith(other *CopyOptions) error {
   165  	if other.Destination != nil {
   166  		if o.Destination != nil {
   167  			return pgerror.Newf(pgcode.Syntax, "destination option specified multiple times")
   168  		}
   169  		o.Destination = other.Destination
   170  	}
   171  	if other.HasFormat {
   172  		if o.HasFormat {
   173  			return pgerror.Newf(pgcode.Syntax, "format option specified multiple times")
   174  		}
   175  		o.CopyFormat = other.CopyFormat
   176  		o.HasFormat = true
   177  	}
   178  	if other.Delimiter != nil {
   179  		if o.Delimiter != nil {
   180  			return pgerror.Newf(pgcode.Syntax, "delimiter option specified multiple times")
   181  		}
   182  		o.Delimiter = other.Delimiter
   183  	}
   184  	if other.Null != nil {
   185  		if o.Null != nil {
   186  			return pgerror.Newf(pgcode.Syntax, "null option specified multiple times")
   187  		}
   188  		o.Null = other.Null
   189  	}
   190  	if other.Escape != nil {
   191  		if o.Escape != nil {
   192  			return pgerror.Newf(pgcode.Syntax, "escape option specified multiple times")
   193  		}
   194  		o.Escape = other.Escape
   195  	}
   196  	if other.HasHeader {
   197  		if o.HasHeader {
   198  			return pgerror.Newf(pgcode.Syntax, "header option specified multiple times")
   199  		}
   200  		o.Header = other.Header
   201  		o.HasHeader = true
   202  	}
   203  	if other.Quote != nil {
   204  		if o.Quote != nil {
   205  			return pgerror.Newf(pgcode.Syntax, "quote option specified multiple times")
   206  		}
   207  		o.Quote = other.Quote
   208  	}
   209  	return nil
   210  }
   211  
   212  // CopyFormat identifies a COPY data format.
   213  type CopyFormat int
   214  
   215  // Valid values for CopyFormat.
   216  const (
   217  	CopyFormatText CopyFormat = iota
   218  	CopyFormatBinary
   219  	CopyFormatCSV
   220  )