github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/output.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 frontend
    16  
    17  import (
    18  	"context"
    19  
    20  	"go.uber.org/zap"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    24  	"github.com/matrixorigin/matrixone/pkg/container/types"
    25  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    26  )
    27  
    28  var _ outputPool = &outputQueue{}
    29  var _ outputPool = &fakeOutputQueue{}
    30  
    31  type outputQueue struct {
    32  	ses          *Session
    33  	ctx          context.Context
    34  	proto        MysqlProtocol
    35  	mrs          *MysqlResultSet
    36  	rowIdx       uint64
    37  	length       uint64
    38  	ep           *ExportConfig
    39  	lineStr      []byte
    40  	showStmtType ShowStatementType
    41  }
    42  
    43  func NewOutputQueue(ctx context.Context, ses *Session, columnCount int, mrs *MysqlResultSet, ep *ExportConfig) *outputQueue {
    44  	const countOfResultSet = 1
    45  	if mrs == nil {
    46  		//Create a new temporary result set per pipeline thread.
    47  		mrs = &MysqlResultSet{}
    48  		//Warning: Don't change ResultColumns in this.
    49  		//Reference the shared ResultColumns of the session among multi-thread.
    50  		sesMrs := ses.GetMysqlResultSet()
    51  		mrs.Columns = sesMrs.Columns
    52  		mrs.Name2Index = sesMrs.Name2Index
    53  
    54  		//group row
    55  		mrs.Data = make([][]interface{}, countOfResultSet)
    56  		for i := 0; i < countOfResultSet; i++ {
    57  			mrs.Data[i] = make([]interface{}, columnCount)
    58  		}
    59  	}
    60  
    61  	if ep == nil {
    62  		ep = ses.GetExportConfig()
    63  	}
    64  
    65  	return &outputQueue{
    66  		ctx:          ctx,
    67  		ses:          ses,
    68  		proto:        ses.GetMysqlProtocol(),
    69  		mrs:          mrs,
    70  		rowIdx:       0,
    71  		length:       uint64(countOfResultSet),
    72  		ep:           ep,
    73  		showStmtType: ses.GetShowStmtType(),
    74  	}
    75  }
    76  
    77  func (oq *outputQueue) resetLineStr() {
    78  	oq.lineStr = oq.lineStr[:0]
    79  }
    80  
    81  func (oq *outputQueue) reset() {}
    82  
    83  /*
    84  getEmptyRow returns an empty space for filling data.
    85  If there is no space, it flushes the data into the protocol
    86  and returns an empty space then.
    87  */
    88  func (oq *outputQueue) getEmptyRow() ([]interface{}, error) {
    89  	if oq.rowIdx >= oq.length {
    90  		if err := oq.flush(); err != nil {
    91  			return nil, err
    92  		}
    93  	}
    94  
    95  	row := oq.mrs.Data[oq.rowIdx]
    96  	oq.rowIdx++
    97  	return row, nil
    98  }
    99  
   100  /*
   101  flush will force the data flushed into the protocol.
   102  */
   103  func (oq *outputQueue) flush() error {
   104  
   105  	if oq.rowIdx <= 0 {
   106  		return nil
   107  	}
   108  	if oq.ep.needExportToFile() {
   109  		if err := exportDataToCSVFile(oq); err != nil {
   110  			logError(oq.ses, oq.ses.GetDebugString(),
   111  				"Error occurred while exporting to CSV file",
   112  				zap.Error(err))
   113  			return err
   114  		}
   115  	} else {
   116  		//send group of row
   117  		if oq.showStmtType == ShowTableStatus {
   118  			oq.rowIdx = 0
   119  			return nil
   120  		}
   121  
   122  		if err := oq.proto.SendResultSetTextBatchRowSpeedup(oq.mrs, oq.rowIdx); err != nil {
   123  			logError(oq.ses, oq.ses.GetDebugString(),
   124  				"Flush error",
   125  				zap.Error(err))
   126  			return err
   127  		}
   128  	}
   129  	oq.rowIdx = 0
   130  	return nil
   131  }
   132  
   133  // extractRowFromEveryVector gets the j row from the every vector and outputs the row
   134  // needCopyBytes : true -- make a copy of the bytes. else not.
   135  // Case 1: needCopyBytes = false.
   136  // For responding the client, we do not make a copy of the bytes. Because the data
   137  // has been written into the tcp conn before the batch.Batch returned to the pipeline.
   138  // Case 2: needCopyBytes = true.
   139  // For the background execution, we need to make a copy of the bytes. Because the data
   140  // has been saved in the session. Later the data will be used but then the batch.Batch has
   141  // been returned to the pipeline and may be reused and changed by the pipeline.
   142  func extractRowFromEveryVector(ctx context.Context, ses FeSession, dataSet *batch.Batch, j int, oq outputPool, needCopyBytes bool) ([]interface{}, error) {
   143  	row, err := oq.getEmptyRow()
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	var rowIndex = j
   148  	for i, vec := range dataSet.Vecs { //col index
   149  		rowIndexBackup := rowIndex
   150  		if vec.IsConstNull() {
   151  			row[i] = nil
   152  			continue
   153  		}
   154  		if vec.IsConst() {
   155  			rowIndex = 0
   156  		}
   157  
   158  		err = extractRowFromVector(ctx, ses, vec, i, row, rowIndex, needCopyBytes)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  		rowIndex = rowIndexBackup
   163  	}
   164  	return row, nil
   165  }
   166  
   167  // extractRowFromVector gets the rowIndex row from the i vector
   168  func extractRowFromVector(ctx context.Context, ses FeSession, vec *vector.Vector, i int, row []interface{}, rowIndex int, needCopyBytes bool) error {
   169  	if vec.IsConstNull() || vec.GetNulls().Contains(uint64(rowIndex)) {
   170  		row[i] = nil
   171  		return nil
   172  	}
   173  
   174  	switch vec.GetType().Oid { //get col
   175  	case types.T_json:
   176  		row[i] = types.DecodeJson(copyBytes(vec.GetBytesAt(rowIndex), needCopyBytes))
   177  	case types.T_bool:
   178  		row[i] = vector.GetFixedAt[bool](vec, rowIndex)
   179  	case types.T_bit:
   180  		row[i] = vector.GetFixedAt[uint64](vec, rowIndex)
   181  	case types.T_int8:
   182  		row[i] = vector.GetFixedAt[int8](vec, rowIndex)
   183  	case types.T_uint8:
   184  		row[i] = vector.GetFixedAt[uint8](vec, rowIndex)
   185  	case types.T_int16:
   186  		row[i] = vector.GetFixedAt[int16](vec, rowIndex)
   187  	case types.T_uint16:
   188  		row[i] = vector.GetFixedAt[uint16](vec, rowIndex)
   189  	case types.T_int32:
   190  		row[i] = vector.GetFixedAt[int32](vec, rowIndex)
   191  	case types.T_uint32:
   192  		row[i] = vector.GetFixedAt[uint32](vec, rowIndex)
   193  	case types.T_int64:
   194  		row[i] = vector.GetFixedAt[int64](vec, rowIndex)
   195  	case types.T_uint64:
   196  		row[i] = vector.GetFixedAt[uint64](vec, rowIndex)
   197  	case types.T_float32:
   198  		row[i] = vector.GetFixedAt[float32](vec, rowIndex)
   199  	case types.T_float64:
   200  		row[i] = vector.GetFixedAt[float64](vec, rowIndex)
   201  	case types.T_char, types.T_varchar, types.T_blob, types.T_text, types.T_binary, types.T_varbinary:
   202  		row[i] = copyBytes(vec.GetBytesAt(rowIndex), needCopyBytes)
   203  	case types.T_array_float32:
   204  		// NOTE: Don't merge it with T_varchar. You will get raw binary in the SQL output
   205  		//+------------------------------+
   206  		//| abs(cast([1,2,3] as vecf32)) |
   207  		//+------------------------------+
   208  		//|   �?   @  @@                  |
   209  		//+------------------------------+
   210  		row[i] = vector.GetArrayAt[float32](vec, rowIndex)
   211  	case types.T_array_float64:
   212  		row[i] = vector.GetArrayAt[float64](vec, rowIndex)
   213  	case types.T_date:
   214  		row[i] = vector.GetFixedAt[types.Date](vec, rowIndex)
   215  	case types.T_datetime:
   216  		scale := vec.GetType().Scale
   217  		row[i] = vector.GetFixedAt[types.Datetime](vec, rowIndex).String2(scale)
   218  	case types.T_time:
   219  		scale := vec.GetType().Scale
   220  		row[i] = vector.GetFixedAt[types.Time](vec, rowIndex).String2(scale)
   221  	case types.T_timestamp:
   222  		scale := vec.GetType().Scale
   223  		timeZone := ses.GetTimeZone()
   224  		row[i] = vector.GetFixedAt[types.Timestamp](vec, rowIndex).String2(timeZone, scale)
   225  	case types.T_decimal64:
   226  		scale := vec.GetType().Scale
   227  		row[i] = vector.GetFixedAt[types.Decimal64](vec, rowIndex).Format(scale)
   228  	case types.T_decimal128:
   229  		scale := vec.GetType().Scale
   230  		row[i] = vector.GetFixedAt[types.Decimal128](vec, rowIndex).Format(scale)
   231  	case types.T_uuid:
   232  		row[i] = vector.GetFixedAt[types.Uuid](vec, rowIndex).ToString()
   233  	case types.T_Rowid:
   234  		row[i] = vector.GetFixedAt[types.Rowid](vec, rowIndex)
   235  	case types.T_Blockid:
   236  		row[i] = vector.GetFixedAt[types.Blockid](vec, rowIndex)
   237  	case types.T_TS:
   238  		row[i] = vector.GetFixedAt[types.TS](vec, rowIndex)
   239  	case types.T_enum:
   240  		row[i] = copyBytes(vec.GetBytesAt(rowIndex), needCopyBytes)
   241  	default:
   242  		logError(ses, ses.GetDebugString(),
   243  			"Failed to extract row from vector, unsupported type",
   244  			zap.Int("typeID", int(vec.GetType().Oid)))
   245  		return moerr.NewInternalError(ctx, "extractRowFromVector : unsupported type %d", vec.GetType().Oid)
   246  	}
   247  	return nil
   248  }
   249  
   250  // fakeOutputQueue saves the data into the session.
   251  type fakeOutputQueue struct {
   252  	mrs *MysqlResultSet
   253  }
   254  
   255  func newFakeOutputQueue(mrs *MysqlResultSet) outputPool {
   256  	return &fakeOutputQueue{mrs: mrs}
   257  }
   258  
   259  func (foq *fakeOutputQueue) resetLineStr() {}
   260  
   261  func (foq *fakeOutputQueue) reset() {}
   262  
   263  func (foq *fakeOutputQueue) getEmptyRow() ([]interface{}, error) {
   264  	row := make([]interface{}, foq.mrs.GetColumnCount())
   265  	foq.mrs.AddRow(row)
   266  	return row, nil
   267  }
   268  
   269  func (foq *fakeOutputQueue) flush() error {
   270  	return nil
   271  }