github.com/matrixorigin/matrixone@v0.7.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  	prefix := ""
    89  	for _, n := range node.Names {
    90  		ctx.WriteString(prefix)
    91  		n.Format(ctx)
    92  		prefix = " "
    93  	}
    94  	ctx.WriteString(" = ")
    95  	if node.Expr != nil {
    96  		node.Expr.Format(ctx)
    97  	}
    98  }
    99  
   100  func NewUpdateExpr(t bool, n []*UnresolvedName, e Expr) *UpdateExpr {
   101  	return &UpdateExpr{
   102  		Tuple: t,
   103  		Names: n,
   104  		Expr:  e,
   105  	}
   106  }
   107  
   108  const (
   109  	AUTO       = "auto"
   110  	NOCOMPRESS = "none"
   111  	GZIP       = "gzip"
   112  	GZ         = "gz" // alias of gzip
   113  	BZIP2      = "bzip2"
   114  	BZ2        = "bz2" // alias for bzip2
   115  	FLATE      = "flate"
   116  	LZW        = "lzw"
   117  	ZLIB       = "zlib"
   118  	LZ4        = "lz4"
   119  )
   120  
   121  // load data fotmat
   122  const (
   123  	CSV      = "csv"
   124  	JSONLINE = "jsonline"
   125  )
   126  
   127  // if $format is jsonline
   128  const (
   129  	OBJECT = "object"
   130  	ARRAY  = "array"
   131  )
   132  
   133  const (
   134  	S3 = 1
   135  )
   136  
   137  type ExternParam struct {
   138  	// params which come from parser
   139  	ExParamConst
   140  	// params which come from internal construct
   141  	ExParam
   142  }
   143  
   144  type ExParamConst struct {
   145  	ScanType     int
   146  	Filepath     string
   147  	CompressType string
   148  	Format       string
   149  	Option       []string
   150  	Tail         *TailParameter
   151  }
   152  
   153  type ExParam struct {
   154  	JsonData    string
   155  	FileService fileservice.FileService
   156  	NullMap     map[string]([]string)
   157  	S3Param     *S3Parameter
   158  	Ctx         context.Context
   159  	LoadFile    bool
   160  	Local       bool
   161  	QueryResult bool
   162  	SysTable    bool
   163  	Parallel    bool
   164  }
   165  
   166  type S3Parameter struct {
   167  	Endpoint   string `json:"s3-test-endpoint"`
   168  	Region     string `json:"s3-test-region"`
   169  	APIKey     string `json:"s3-test-key"`
   170  	APISecret  string `json:"s3-test-secret"`
   171  	Bucket     string `json:"s3-test-bucket"`
   172  	Provider   string `json:"s3-test-rovider"`
   173  	RoleArn    string `json:"s3-test-rolearn"`
   174  	ExternalId string `json:"s3-test-externalid"`
   175  }
   176  
   177  type TailParameter struct {
   178  	//Fields
   179  	Fields *Fields
   180  	//Lines
   181  	Lines *Lines
   182  	//Ignored lines
   183  	IgnoredLines uint64
   184  	//col_name_or_user_var
   185  	ColumnList []LoadColumn
   186  	//set col_name
   187  	Assignments UpdateExprs
   188  }
   189  
   190  // Load data statement
   191  type Load struct {
   192  	statementImpl
   193  	Local             bool
   194  	DuplicateHandling DuplicateKey
   195  	Table             *TableName
   196  	Accounts          IdentifierList
   197  	//Partition
   198  	Param *ExternParam
   199  }
   200  
   201  type Import struct {
   202  	statementImpl
   203  	Local             bool
   204  	DuplicateHandling DuplicateKey
   205  	Table             *TableName
   206  	//Partition
   207  	Param *ExternParam
   208  }
   209  
   210  func (node *Load) Format(ctx *FmtCtx) {
   211  	ctx.WriteString("load data")
   212  	if node.Local {
   213  		ctx.WriteString(" local")
   214  	}
   215  
   216  	if len(node.Param.Option) == 0 {
   217  		ctx.WriteString(" infile ")
   218  		ctx.WriteString(node.Param.Filepath)
   219  	} else {
   220  		if node.Param.ScanType == S3 {
   221  			ctx.WriteString(" url s3option ")
   222  		} else {
   223  			ctx.WriteString(" infile ")
   224  
   225  		}
   226  		ctx.WriteString("{")
   227  		for i := 0; i < len(node.Param.Option); i += 2 {
   228  			switch strings.ToLower(node.Param.Option[i]) {
   229  			case "endpoint":
   230  				ctx.WriteString("'endpoint'='" + node.Param.Option[i+1] + "'")
   231  			case "region":
   232  				ctx.WriteString("'region'='" + node.Param.Option[i+1] + "'")
   233  			case "access_key_id":
   234  				ctx.WriteString("'access_key_id'='" + node.Param.Option[i+1] + "'")
   235  			case "secret_access_key":
   236  				ctx.WriteString("'secret_access_key'='" + node.Param.Option[i+1] + "'")
   237  			case "bucket":
   238  				ctx.WriteString("'bucket'='" + node.Param.Option[i+1] + "'")
   239  			case "filepath":
   240  				ctx.WriteString("'filepath'='" + node.Param.Option[i+1] + "'")
   241  			case "compression":
   242  				ctx.WriteString("'compression'='" + node.Param.Option[i+1] + "'")
   243  			case "format":
   244  				ctx.WriteString("'format'='" + node.Param.Option[i+1] + "'")
   245  			case "jsondata":
   246  				ctx.WriteString("'jsondata'='" + node.Param.Option[i+1] + "'")
   247  			}
   248  			if i != len(node.Param.Option)-2 {
   249  				ctx.WriteString(", ")
   250  			}
   251  		}
   252  		ctx.WriteString("}")
   253  	}
   254  
   255  	switch node.DuplicateHandling.(type) {
   256  	case *DuplicateKeyError:
   257  		break
   258  	case *DuplicateKeyIgnore:
   259  		ctx.WriteString(" ignore")
   260  	case *DuplicateKeyReplace:
   261  		ctx.WriteString(" replace")
   262  	}
   263  	ctx.WriteString(" into table ")
   264  	node.Table.Format(ctx)
   265  
   266  	if node.Accounts != nil {
   267  		ctx.WriteString(" accounts(")
   268  		node.Accounts.Format(ctx)
   269  		ctx.WriteByte(')')
   270  	}
   271  
   272  	if node.Param.Tail.Fields != nil {
   273  		ctx.WriteByte(' ')
   274  		node.Param.Tail.Fields.Format(ctx)
   275  	}
   276  
   277  	if node.Param.Tail.Lines != nil {
   278  		ctx.WriteByte(' ')
   279  		node.Param.Tail.Lines.Format(ctx)
   280  	}
   281  
   282  	if node.Param.Tail.IgnoredLines != 0 {
   283  		ctx.WriteString(" ignore ")
   284  		ctx.WriteString(strconv.FormatUint(node.Param.Tail.IgnoredLines, 10))
   285  		ctx.WriteString(" lines")
   286  	}
   287  	if node.Param.Tail.ColumnList != nil {
   288  		prefix := " ("
   289  		for _, c := range node.Param.Tail.ColumnList {
   290  			ctx.WriteString(prefix)
   291  			c.Format(ctx)
   292  			prefix = ", "
   293  		}
   294  		ctx.WriteByte(')')
   295  	}
   296  	if node.Param.Tail.Assignments != nil {
   297  		ctx.WriteString(" set ")
   298  		node.Param.Tail.Assignments.Format(ctx)
   299  	}
   300  }
   301  
   302  func (node *Load) GetStatementType() string { return "Load" }
   303  func (node *Load) GetQueryType() string     { return QueryTypeDML }
   304  
   305  func (node *Import) Format(ctx *FmtCtx) {
   306  	ctx.WriteString("import data")
   307  	if node.Local {
   308  		ctx.WriteString(" local")
   309  	}
   310  
   311  	if node.Param.CompressType == AUTO || node.Param.CompressType == NOCOMPRESS {
   312  		ctx.WriteString(" infile ")
   313  		ctx.WriteString(node.Param.Filepath)
   314  	} else {
   315  		ctx.WriteString(" infile ")
   316  		ctx.WriteString("{'filepath':'" + node.Param.Filepath + "', 'compression':'" + strings.ToLower(node.Param.CompressType) + "'}")
   317  	}
   318  
   319  	switch node.DuplicateHandling.(type) {
   320  	case *DuplicateKeyError:
   321  		break
   322  	case *DuplicateKeyIgnore:
   323  		ctx.WriteString(" ignore")
   324  	case *DuplicateKeyReplace:
   325  		ctx.WriteString(" replace")
   326  	}
   327  	ctx.WriteString(" into table ")
   328  	node.Table.Format(ctx)
   329  
   330  	if node.Param.Tail.Fields != nil {
   331  		ctx.WriteByte(' ')
   332  		node.Param.Tail.Fields.Format(ctx)
   333  	}
   334  
   335  	if node.Param.Tail.Lines != nil {
   336  		ctx.WriteByte(' ')
   337  		node.Param.Tail.Lines.Format(ctx)
   338  	}
   339  
   340  	if node.Param.Tail.IgnoredLines != 0 {
   341  		ctx.WriteString(" ignore ")
   342  		ctx.WriteString(strconv.FormatUint(node.Param.Tail.IgnoredLines, 10))
   343  		ctx.WriteString(" lines")
   344  	}
   345  	if node.Param.Tail.ColumnList != nil {
   346  		prefix := " ("
   347  		for _, c := range node.Param.Tail.ColumnList {
   348  			ctx.WriteString(prefix)
   349  			c.Format(ctx)
   350  			prefix = ", "
   351  		}
   352  		ctx.WriteByte(')')
   353  	}
   354  	if node.Param.Tail.Assignments != nil {
   355  		ctx.WriteString(" set ")
   356  		node.Param.Tail.Assignments.Format(ctx)
   357  	}
   358  }
   359  
   360  func (node *Import) GetStatementType() string { return "Import" }
   361  func (node *Import) GetQueryType() string     { return QueryTypeDML }
   362  
   363  type DuplicateKey interface{}
   364  
   365  type duplicateKeyImpl struct {
   366  	DuplicateKey
   367  }
   368  
   369  type DuplicateKeyError struct {
   370  	duplicateKeyImpl
   371  }
   372  
   373  func NewDuplicateKeyError() *DuplicateKeyError {
   374  	return &DuplicateKeyError{}
   375  }
   376  
   377  type DuplicateKeyReplace struct {
   378  	duplicateKeyImpl
   379  }
   380  
   381  func NewDuplicateKeyReplace() *DuplicateKeyReplace {
   382  	return &DuplicateKeyReplace{}
   383  }
   384  
   385  type DuplicateKeyIgnore struct {
   386  	duplicateKeyImpl
   387  }
   388  
   389  func NewDuplicateKeyIgnore() *DuplicateKeyIgnore {
   390  	return &DuplicateKeyIgnore{}
   391  }
   392  
   393  type Fields struct {
   394  	Terminated string
   395  	Optionally bool
   396  	EnclosedBy byte
   397  	EscapedBy  byte
   398  }
   399  
   400  func (node *Fields) Format(ctx *FmtCtx) {
   401  	ctx.WriteString("fields")
   402  	prefix := ""
   403  	if node.Terminated != "" {
   404  		ctx.WriteString(" terminated by ")
   405  		ctx.WriteStringQuote(node.Terminated)
   406  		prefix = " "
   407  	}
   408  	if node.Optionally {
   409  		ctx.WriteString(prefix)
   410  		ctx.WriteString("optionally enclosed by ")
   411  		ctx.WriteStringQuote(string(node.EnclosedBy))
   412  	} else if node.EnclosedBy != 0 {
   413  		ctx.WriteString(prefix)
   414  		ctx.WriteString("enclosed by ")
   415  		ctx.WriteStringQuote(string(node.EnclosedBy))
   416  	}
   417  	if node.EscapedBy != 0 {
   418  		ctx.WriteString(prefix)
   419  		ctx.WriteString("escaped by ")
   420  		ctx.WriteStringQuote(string(node.EscapedBy))
   421  	}
   422  }
   423  
   424  func NewFields(t string, o bool, en byte, es byte) *Fields {
   425  	return &Fields{
   426  		Terminated: t,
   427  		Optionally: o,
   428  		EnclosedBy: en,
   429  		EscapedBy:  es,
   430  	}
   431  }
   432  
   433  type Lines struct {
   434  	StartingBy   string
   435  	TerminatedBy string
   436  }
   437  
   438  func (node *Lines) Format(ctx *FmtCtx) {
   439  	ctx.WriteString("lines")
   440  	if node.StartingBy != "" {
   441  		ctx.WriteString(" starting by ")
   442  		ctx.WriteStringQuote(node.StartingBy)
   443  	}
   444  	if node.TerminatedBy != "" {
   445  		ctx.WriteString(" terminated by ")
   446  		ctx.WriteStringQuote(node.TerminatedBy)
   447  	}
   448  }
   449  
   450  func NewLines(s string, t string) *Lines {
   451  	return &Lines{
   452  		StartingBy:   s,
   453  		TerminatedBy: t,
   454  	}
   455  }
   456  
   457  // column element in load data column list
   458  type LoadColumn interface {
   459  	NodeFormatter
   460  }
   461  
   462  type ExportParam struct {
   463  	// outfile flag
   464  	Outfile bool
   465  	// query id
   466  	QueryId string
   467  	// filename path
   468  	FilePath string
   469  	// Fields
   470  	Fields *Fields
   471  	// Lines
   472  	Lines *Lines
   473  	// fileSize
   474  	MaxFileSize uint64
   475  	// header flag
   476  	Header     bool
   477  	ForceQuote []string
   478  }
   479  
   480  func (ep *ExportParam) Format(ctx *FmtCtx) {
   481  	if ep.FilePath == "" {
   482  		return
   483  	}
   484  	ep.format(ctx, true)
   485  }
   486  
   487  func (ep *ExportParam) format(ctx *FmtCtx, withOutfile bool) {
   488  	ctx.WriteString("into")
   489  	if withOutfile {
   490  		ctx.WriteString(" outfile")
   491  	}
   492  	ctx.WriteByte(' ')
   493  	ctx.WriteString(ep.FilePath)
   494  	if ep.Fields != nil {
   495  		ctx.WriteByte(' ')
   496  		ep.Fields.Format(ctx)
   497  	}
   498  	if ep.Lines != nil {
   499  		ctx.WriteByte(' ')
   500  		ep.Lines.Format(ctx)
   501  	}
   502  	ctx.WriteString(" header ")
   503  	if ep.Header {
   504  		ctx.WriteString("true")
   505  	} else {
   506  		ctx.WriteString("false")
   507  	}
   508  	if ep.MaxFileSize != 0 {
   509  		ctx.WriteString(" max_file_size ")
   510  		ctx.WriteString(strconv.FormatUint(ep.MaxFileSize, 10))
   511  	}
   512  	if len(ep.ForceQuote) > 0 {
   513  		ctx.WriteString(" force_quote")
   514  		prefix := " "
   515  		for i := 0; i < len(ep.ForceQuote); i++ {
   516  			ctx.WriteString(prefix)
   517  			ctx.WriteString(ep.ForceQuote[i])
   518  			prefix = ", "
   519  		}
   520  	}
   521  }
   522  
   523  var _ LoadColumn = &UnresolvedName{}
   524  var _ LoadColumn = &VarExpr{}