github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/parsers/tree/update.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tree 16 17 import ( 18 "context" 19 "strconv" 20 "strings" 21 22 "github.com/matrixorigin/matrixone/pkg/fileservice" 23 ) 24 25 // update statement 26 type Update struct { 27 statementImpl 28 Tables TableExprs 29 Exprs UpdateExprs 30 Where *Where 31 OrderBy OrderBy 32 Limit *Limit 33 With *With 34 } 35 36 func (node *Update) Format(ctx *FmtCtx) { 37 if node.With != nil { 38 node.With.Format(ctx) 39 ctx.WriteByte(' ') 40 } 41 ctx.WriteString("update") 42 if node.Tables != nil { 43 ctx.WriteByte(' ') 44 node.Tables.Format(ctx) 45 } 46 ctx.WriteString(" set") 47 if node.Exprs != nil { 48 ctx.WriteByte(' ') 49 node.Exprs.Format(ctx) 50 } 51 if node.Where != nil { 52 ctx.WriteByte(' ') 53 node.Where.Format(ctx) 54 } 55 if len(node.OrderBy) > 0 { 56 ctx.WriteByte(' ') 57 node.OrderBy.Format(ctx) 58 } 59 if node.Limit != nil { 60 ctx.WriteByte(' ') 61 node.Limit.Format(ctx) 62 } 63 } 64 65 func (node *Update) GetStatementType() string { return "Update" } 66 func (node *Update) GetQueryType() string { return QueryTypeDML } 67 68 type UpdateExprs []*UpdateExpr 69 70 func (node *UpdateExprs) Format(ctx *FmtCtx) { 71 prefix := "" 72 for _, u := range *node { 73 ctx.WriteString(prefix) 74 u.Format(ctx) 75 prefix = ", " 76 } 77 } 78 79 // the update expression. 80 type UpdateExpr struct { 81 NodeFormatter 82 Tuple bool 83 Names []*UnresolvedName 84 Expr Expr 85 } 86 87 func (node *UpdateExpr) Format(ctx *FmtCtx) { 88 if node == nil { 89 return 90 } 91 prefix := "" 92 for _, n := range node.Names { 93 ctx.WriteString(prefix) 94 n.Format(ctx) 95 prefix = " " 96 } 97 ctx.WriteString(" = ") 98 if node.Expr != nil { 99 node.Expr.Format(ctx) 100 } 101 } 102 103 func NewUpdateExpr(t bool, n []*UnresolvedName, e Expr) *UpdateExpr { 104 return &UpdateExpr{ 105 Tuple: t, 106 Names: n, 107 Expr: e, 108 } 109 } 110 111 const ( 112 AUTO = "auto" 113 NOCOMPRESS = "none" 114 GZIP = "gzip" 115 GZ = "gz" // alias of gzip 116 BZIP2 = "bzip2" 117 BZ2 = "bz2" // alias for bzip2 118 FLATE = "flate" 119 LZW = "lzw" 120 ZLIB = "zlib" 121 LZ4 = "lz4" 122 TAR_GZ = "tar.gz" 123 TAR_BZ2 = "tar.bz2" 124 ) 125 126 // load data fotmat 127 const ( 128 CSV = "csv" 129 JSONLINE = "jsonline" 130 PARQUET = "parquet" 131 ) 132 133 // if $format is jsonline 134 const ( 135 OBJECT = "object" 136 ARRAY = "array" 137 ) 138 139 const ( 140 S3 = 1 141 INLINE = 2 142 ) 143 144 type ExternParam struct { 145 // params which come from parser 146 ExParamConst 147 // params which come from internal construct 148 ExParam 149 } 150 151 type ExParamConst struct { 152 Init bool 153 ScanType int 154 FileSize int64 155 Filepath string 156 CompressType string 157 Format string 158 Option []string 159 Data string 160 Tail *TailParameter 161 StageName Identifier 162 } 163 164 type ExParam struct { 165 JsonData string 166 FileService fileservice.FileService 167 NullMap map[string]([]string) 168 S3Param *S3Parameter 169 Ctx context.Context 170 LoadFile bool 171 Local bool 172 QueryResult bool 173 SysTable bool 174 Parallel bool 175 Strict bool 176 } 177 178 type S3Parameter struct { 179 Endpoint string `json:"s3-test-endpoint"` 180 Region string `json:"s3-test-region"` 181 APIKey string `json:"s3-test-key"` 182 APISecret string `json:"s3-test-secret"` 183 Bucket string `json:"s3-test-bucket"` 184 Provider string `json:"s3-test-rovider"` 185 RoleArn string `json:"s3-test-rolearn"` 186 ExternalId string `json:"s3-test-externalid"` 187 } 188 189 type TailParameter struct { 190 //Charset 191 Charset string 192 //Fields 193 Fields *Fields 194 //Lines 195 Lines *Lines 196 //Ignored lines 197 IgnoredLines uint64 198 //col_name_or_user_var 199 ColumnList []LoadColumn 200 //set col_name 201 Assignments UpdateExprs 202 } 203 204 // Load data statement 205 type Load struct { 206 statementImpl 207 Local bool 208 DuplicateHandling DuplicateKey 209 Table *TableName 210 Accounts IdentifierList 211 //Partition 212 Param *ExternParam 213 } 214 215 func (node *Load) Format(ctx *FmtCtx) { 216 ctx.WriteString("load data") 217 if node.Local { 218 ctx.WriteString(" local") 219 } 220 if len(node.Param.StageName) != 0 { 221 ctx.WriteString(" url from stage ") 222 node.Param.StageName.Format(ctx) 223 } else { 224 if node.Param.ScanType == INLINE { 225 ctx.WriteString(" inline format='") 226 ctx.WriteString(node.Param.Format) 227 ctx.WriteString("', data='") 228 ctx.WriteString(node.Param.Data) 229 if node.Param.JsonData == "" { 230 ctx.WriteString("'") 231 } else { 232 ctx.WriteString("', jsontype='") 233 ctx.WriteString(node.Param.JsonData) 234 ctx.WriteString("'") 235 } 236 } else { 237 if len(node.Param.Option) == 0 { 238 ctx.WriteString(" infile ") 239 ctx.WriteString(node.Param.Filepath) 240 } else { 241 if node.Param.ScanType == S3 { 242 ctx.WriteString(" url s3option ") 243 } else { 244 ctx.WriteString(" infile ") 245 } 246 formatS3option(ctx, node.Param.Option) 247 } 248 } 249 } 250 251 switch node.DuplicateHandling.(type) { 252 case *DuplicateKeyError: 253 break 254 case *DuplicateKeyIgnore: 255 ctx.WriteString(" ignore") 256 case *DuplicateKeyReplace: 257 ctx.WriteString(" replace") 258 } 259 ctx.WriteString(" into table ") 260 node.Table.Format(ctx) 261 262 if node.Accounts != nil { 263 ctx.WriteString(" accounts(") 264 node.Accounts.Format(ctx) 265 ctx.WriteByte(')') 266 } 267 268 if len(node.Param.Tail.Charset) != 0 { 269 ctx.WriteByte(' ') 270 ctx.WriteString("character set ") 271 ctx.WriteString(node.Param.Tail.Charset) 272 } 273 274 if node.Param.Tail.Fields != nil { 275 ctx.WriteByte(' ') 276 node.Param.Tail.Fields.Format(ctx) 277 } 278 279 if node.Param.Tail.Lines != nil { 280 ctx.WriteByte(' ') 281 node.Param.Tail.Lines.Format(ctx) 282 } 283 284 if node.Param.Tail.IgnoredLines != 0 { 285 ctx.WriteString(" ignore ") 286 ctx.WriteString(strconv.FormatUint(node.Param.Tail.IgnoredLines, 10)) 287 ctx.WriteString(" lines") 288 } 289 if node.Param.Tail.ColumnList != nil { 290 prefix := " (" 291 for _, c := range node.Param.Tail.ColumnList { 292 ctx.WriteString(prefix) 293 c.Format(ctx) 294 prefix = ", " 295 } 296 ctx.WriteByte(')') 297 } 298 if node.Param.Tail.Assignments != nil { 299 ctx.WriteString(" set ") 300 node.Param.Tail.Assignments.Format(ctx) 301 } 302 if node.Param.Parallel { 303 ctx.WriteString(" parallel true ") 304 if node.Param.Strict { 305 ctx.WriteString("strict true ") 306 } 307 } 308 } 309 310 func formatS3option(ctx *FmtCtx, option []string) { 311 ctx.WriteString("{") 312 for i := 0; i < len(option); i += 2 { 313 switch strings.ToLower(option[i]) { 314 case "endpoint": 315 ctx.WriteString("'endpoint'='" + option[i+1] + "'") 316 case "region": 317 ctx.WriteString("'region'='" + option[i+1] + "'") 318 case "access_key_id": 319 ctx.WriteString("'access_key_id'='******'") 320 case "secret_access_key": 321 ctx.WriteString("'secret_access_key'='******'") 322 case "bucket": 323 ctx.WriteString("'bucket'='" + option[i+1] + "'") 324 case "filepath": 325 ctx.WriteString("'filepath'='" + option[i+1] + "'") 326 case "compression": 327 ctx.WriteString("'compression'='" + option[i+1] + "'") 328 case "format": 329 ctx.WriteString("'format'='" + option[i+1] + "'") 330 case "jsondata": 331 ctx.WriteString("'jsondata'='" + option[i+1] + "'") 332 case "role_arn": 333 ctx.WriteString("'role_arn'='" + option[i+1] + "'") 334 case "external_id": 335 ctx.WriteString("'external_id'='" + option[i+1] + "'") 336 } 337 if i != len(option)-2 { 338 ctx.WriteString(", ") 339 } 340 } 341 ctx.WriteString("}") 342 } 343 344 func (node *Load) GetStatementType() string { return "Load" } 345 func (node *Load) GetQueryType() string { return QueryTypeDML } 346 347 type DuplicateKey interface{} 348 349 type duplicateKeyImpl struct { 350 DuplicateKey 351 } 352 353 type DuplicateKeyError struct { 354 duplicateKeyImpl 355 } 356 357 func NewDuplicateKeyError() *DuplicateKeyError { 358 return &DuplicateKeyError{} 359 } 360 361 type DuplicateKeyReplace struct { 362 duplicateKeyImpl 363 } 364 365 func NewDuplicateKeyReplace() *DuplicateKeyReplace { 366 return &DuplicateKeyReplace{} 367 } 368 369 type DuplicateKeyIgnore struct { 370 duplicateKeyImpl 371 } 372 373 func NewDuplicateKeyIgnore() *DuplicateKeyIgnore { 374 return &DuplicateKeyIgnore{} 375 } 376 377 type EscapedBy struct { 378 Value byte 379 } 380 381 type EnclosedBy struct { 382 Value byte 383 } 384 385 type Terminated struct { 386 Value string 387 } 388 389 type Fields struct { 390 Terminated *Terminated 391 Optionally bool 392 EnclosedBy *EnclosedBy 393 EscapedBy *EscapedBy 394 } 395 396 func (node *Fields) Format(ctx *FmtCtx) { 397 ctx.WriteString("fields") 398 prefix := "" 399 if node.Terminated != nil { 400 ctx.WriteString(" terminated by ") 401 if node.Terminated.Value == "" { 402 ctx.WriteString("''") 403 } else { 404 ctx.WriteStringQuote(node.Terminated.Value) 405 } 406 prefix = " " 407 } 408 if node.Optionally { 409 ctx.WriteString(prefix) 410 ctx.WriteString("optionally enclosed by ") 411 if node.EnclosedBy.Value == 0 { 412 ctx.WriteString("''") 413 } else { 414 ctx.WriteStringQuote(string(node.EnclosedBy.Value)) 415 } 416 } else if node.EnclosedBy != nil && node.EnclosedBy.Value != 0 { 417 ctx.WriteString(prefix) 418 ctx.WriteString("enclosed by ") 419 ctx.WriteStringQuote(string(node.EnclosedBy.Value)) 420 } 421 if node.EscapedBy != nil { 422 ctx.WriteString(prefix) 423 ctx.WriteString("escaped by ") 424 if node.EscapedBy.Value == 0 { 425 ctx.WriteString("''") 426 } else { 427 ctx.WriteStringQuote(string(node.EscapedBy.Value)) 428 } 429 } 430 } 431 432 func NewFields(t string, o bool, en byte, es byte) *Fields { 433 return &Fields{ 434 Terminated: &Terminated{ 435 Value: t, 436 }, 437 Optionally: o, 438 EnclosedBy: &EnclosedBy{ 439 Value: en, 440 }, 441 EscapedBy: &EscapedBy{ 442 Value: es, 443 }, 444 } 445 } 446 447 type Lines struct { 448 StartingBy string 449 TerminatedBy *Terminated 450 } 451 452 func (node *Lines) Format(ctx *FmtCtx) { 453 ctx.WriteString("lines") 454 if node.StartingBy != "" { 455 ctx.WriteString(" starting by ") 456 ctx.WriteStringQuote(node.StartingBy) 457 } 458 if node.TerminatedBy != nil { 459 ctx.WriteString(" terminated by ") 460 if node.TerminatedBy.Value == "" { 461 ctx.WriteString("''") 462 } else { 463 ctx.WriteStringQuote(node.TerminatedBy.Value) 464 } 465 } 466 } 467 468 func NewLines(s string, t string) *Lines { 469 return &Lines{ 470 StartingBy: s, 471 TerminatedBy: &Terminated{ 472 Value: t, 473 }, 474 } 475 } 476 477 // column element in load data column list 478 type LoadColumn interface { 479 NodeFormatter 480 } 481 482 type ExportParam struct { 483 // outfile flag 484 Outfile bool 485 // query id 486 QueryId string 487 // filename path 488 FilePath string 489 // Fields 490 Fields *Fields 491 // Lines 492 Lines *Lines 493 // fileSize 494 MaxFileSize uint64 495 // header flag 496 Header bool 497 ForceQuote []string 498 // stage filename path 499 StageFilePath string 500 } 501 502 func (ep *ExportParam) Format(ctx *FmtCtx) { 503 if ep.FilePath == "" { 504 return 505 } 506 ep.format(ctx, true) 507 } 508 509 func (ep *ExportParam) format(ctx *FmtCtx, withOutfile bool) { 510 ctx.WriteString("into") 511 if withOutfile { 512 ctx.WriteString(" outfile") 513 } 514 ctx.WriteByte(' ') 515 ctx.WriteString(ep.FilePath) 516 if ep.Fields != nil { 517 ctx.WriteByte(' ') 518 ep.Fields.Format(ctx) 519 } 520 if ep.Lines != nil { 521 ctx.WriteByte(' ') 522 ep.Lines.Format(ctx) 523 } 524 ctx.WriteString(" header ") 525 if ep.Header { 526 ctx.WriteString("true") 527 } else { 528 ctx.WriteString("false") 529 } 530 if ep.MaxFileSize != 0 { 531 ctx.WriteString(" max_file_size ") 532 ctx.WriteString(strconv.FormatUint(ep.MaxFileSize, 10)) 533 } 534 if len(ep.ForceQuote) > 0 { 535 ctx.WriteString(" force_quote") 536 prefix := " " 537 for i := 0; i < len(ep.ForceQuote); i++ { 538 ctx.WriteString(prefix) 539 ctx.WriteString(ep.ForceQuote[i]) 540 prefix = ", " 541 } 542 } 543 } 544 545 var _ LoadColumn = &UnresolvedName{} 546 var _ LoadColumn = &VarExpr{}