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{}