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 )