go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/mysql/visibility.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package mysql
    26  
    27  import (
    28  	"context"
    29  	"database/sql"
    30  	"errors"
    31  	"fmt"
    32  
    33  	"go.temporal.io/server/common/persistence/sql/sqlplugin"
    34  	"go.temporal.io/server/common/persistence/visibility/store"
    35  )
    36  
    37  const (
    38  	templateCreateWorkflowExecutionStarted = `INSERT INTO executions_visibility (` +
    39  		`namespace_id, workflow_id, run_id, start_time, execution_time, workflow_type_name, status, memo, encoding, task_queue) ` +
    40  		`VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` +
    41  		`ON DUPLICATE KEY UPDATE ` +
    42  		`run_id=VALUES(run_id)`
    43  
    44  	templateCreateWorkflowExecutionClosed = `INSERT INTO executions_visibility (` +
    45  		`namespace_id, workflow_id, run_id, start_time, execution_time, workflow_type_name, close_time, status, history_length, memo, encoding, task_queue) ` +
    46  		`VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` +
    47  		`ON DUPLICATE KEY UPDATE workflow_id = VALUES(workflow_id), start_time = VALUES(start_time), execution_time = VALUES(execution_time), workflow_type_name = VALUES(workflow_type_name), ` +
    48  		`close_time = VALUES(close_time), status = VALUES(status), history_length = VALUES(history_length), memo = VALUES(memo), encoding = VALUES(encoding), task_queue = VALUES(task_queue)`
    49  
    50  	// RunID condition is needed for correct pagination
    51  	templateConditions = ` AND namespace_id = ?
    52  		 AND start_time >= ?
    53  		 AND start_time <= ?
    54   		 AND ((run_id > ? and start_time = ?) OR (start_time < ?))
    55           ORDER BY start_time DESC, run_id
    56  		 LIMIT ?`
    57  
    58  	templateConditionsClosedWorkflows = ` AND namespace_id = ?
    59  	AND close_time >= ?
    60  	AND close_time <= ?
    61  	 AND ((run_id > ? and close_time = ?) OR (close_time < ?))
    62  	ORDER BY close_time DESC, run_id
    63  	LIMIT ?`
    64  
    65  	templateOpenFieldNames = `workflow_id, run_id, start_time, execution_time, workflow_type_name, status, memo, encoding, task_queue`
    66  	templateOpenSelect     = `SELECT ` + templateOpenFieldNames + ` FROM executions_visibility WHERE status = 1 `
    67  
    68  	templateClosedSelect = `SELECT ` + templateOpenFieldNames + `, close_time, history_length
    69  		 FROM executions_visibility WHERE status != 1 `
    70  
    71  	templateGetOpenWorkflowExecutions = templateOpenSelect + templateConditions
    72  
    73  	templateGetClosedWorkflowExecutions = templateClosedSelect + templateConditionsClosedWorkflows
    74  
    75  	templateGetOpenWorkflowExecutionsByType = templateOpenSelect + `AND workflow_type_name = ?` + templateConditions
    76  
    77  	templateGetClosedWorkflowExecutionsByType = templateClosedSelect + `AND workflow_type_name = ?` + templateConditionsClosedWorkflows
    78  
    79  	templateGetOpenWorkflowExecutionsByID = templateOpenSelect + `AND workflow_id = ?` + templateConditions
    80  
    81  	templateGetClosedWorkflowExecutionsByID = templateClosedSelect + `AND workflow_id = ?` + templateConditionsClosedWorkflows
    82  
    83  	templateGetClosedWorkflowExecutionsByStatus = templateClosedSelect + `AND status = ?` + templateConditionsClosedWorkflows
    84  
    85  	templateGetClosedWorkflowExecution = `SELECT workflow_id, run_id, start_time, execution_time, memo, encoding, close_time, workflow_type_name, status, history_length, task_queue 
    86  		 FROM executions_visibility
    87  		 WHERE namespace_id = ? AND status != 1
    88  		 AND run_id = ?`
    89  
    90  	templateGetWorkflowExecution = `
    91  		SELECT
    92  			workflow_id,
    93  			run_id,
    94  			start_time,
    95  			execution_time,
    96  			memo,
    97  			encoding,
    98  			close_time,
    99  			workflow_type_name,
   100  			status,
   101  			history_length,
   102  			task_queue 
   103  		FROM executions_visibility
   104  		WHERE namespace_id = ? AND run_id = ?`
   105  
   106  	templateDeleteWorkflowExecution = "DELETE FROM executions_visibility WHERE namespace_id = ? AND run_id = ?"
   107  )
   108  
   109  var errCloseParams = errors.New("missing one of {CloseTime, HistoryLength} params")
   110  
   111  // InsertIntoVisibility inserts a row into visibility table. If an row already exist,
   112  // its left as such and no update will be made
   113  func (mdb *db) InsertIntoVisibility(
   114  	ctx context.Context,
   115  	row *sqlplugin.VisibilityRow,
   116  ) (sql.Result, error) {
   117  	row.StartTime = mdb.converter.ToMySQLDateTime(row.StartTime)
   118  	row.ExecutionTime = mdb.converter.ToMySQLDateTime(row.ExecutionTime)
   119  	return mdb.conn.ExecContext(ctx,
   120  		templateCreateWorkflowExecutionStarted,
   121  		row.NamespaceID,
   122  		row.WorkflowID,
   123  		row.RunID,
   124  		row.StartTime,
   125  		row.ExecutionTime,
   126  		row.WorkflowTypeName,
   127  		row.Status,
   128  		row.Memo,
   129  		row.Encoding,
   130  		row.TaskQueue,
   131  	)
   132  }
   133  
   134  // ReplaceIntoVisibility replaces an existing row if it exist or creates a new row in visibility table
   135  func (mdb *db) ReplaceIntoVisibility(
   136  	ctx context.Context,
   137  	row *sqlplugin.VisibilityRow,
   138  ) (sql.Result, error) {
   139  	switch {
   140  	case row.CloseTime != nil && row.HistoryLength != nil:
   141  		row.StartTime = mdb.converter.ToMySQLDateTime(row.StartTime)
   142  		row.ExecutionTime = mdb.converter.ToMySQLDateTime(row.ExecutionTime)
   143  		closeTime := mdb.converter.ToMySQLDateTime(*row.CloseTime)
   144  		return mdb.conn.ExecContext(ctx,
   145  			templateCreateWorkflowExecutionClosed,
   146  			row.NamespaceID,
   147  			row.WorkflowID,
   148  			row.RunID,
   149  			row.StartTime,
   150  			row.ExecutionTime,
   151  			row.WorkflowTypeName,
   152  			closeTime,
   153  			row.Status,
   154  			*row.HistoryLength,
   155  			row.Memo,
   156  			row.Encoding,
   157  			row.TaskQueue,
   158  		)
   159  	default:
   160  		return nil, errCloseParams
   161  	}
   162  }
   163  
   164  // DeleteFromVisibility deletes a row from visibility table if it exist
   165  func (mdb *db) DeleteFromVisibility(
   166  	ctx context.Context,
   167  	filter sqlplugin.VisibilityDeleteFilter,
   168  ) (sql.Result, error) {
   169  	return mdb.conn.ExecContext(ctx,
   170  		templateDeleteWorkflowExecution,
   171  		filter.NamespaceID,
   172  		filter.RunID,
   173  	)
   174  }
   175  
   176  // SelectFromVisibility reads one or more rows from visibility table
   177  func (mdb *db) SelectFromVisibility(
   178  	ctx context.Context,
   179  	filter sqlplugin.VisibilitySelectFilter,
   180  ) ([]sqlplugin.VisibilityRow, error) {
   181  	var err error
   182  	var rows []sqlplugin.VisibilityRow
   183  	if filter.MinTime != nil {
   184  		*filter.MinTime = mdb.converter.ToMySQLDateTime(*filter.MinTime)
   185  	}
   186  	if filter.MaxTime != nil {
   187  		*filter.MaxTime = mdb.converter.ToMySQLDateTime(*filter.MaxTime)
   188  	}
   189  	// If filter.Status == 0 (UNSPECIFIED) then only closed workflows will be returned (all excluding 1 (RUNNING)).
   190  	switch {
   191  	case filter.MinTime == nil && filter.RunID != nil && filter.Status != 1:
   192  		var row sqlplugin.VisibilityRow
   193  		err = mdb.conn.GetContext(ctx,
   194  			&row,
   195  			templateGetClosedWorkflowExecution,
   196  			filter.NamespaceID,
   197  			*filter.RunID,
   198  		)
   199  		if err == nil {
   200  			rows = append(rows, row)
   201  		}
   202  	case filter.MinTime != nil && filter.MaxTime != nil &&
   203  		filter.WorkflowID != nil && filter.RunID != nil && filter.PageSize != nil:
   204  		qry := templateGetOpenWorkflowExecutionsByID
   205  		if filter.Status != 1 {
   206  			qry = templateGetClosedWorkflowExecutionsByID
   207  		}
   208  		err = mdb.conn.SelectContext(ctx,
   209  			&rows,
   210  			qry,
   211  			*filter.WorkflowID,
   212  			filter.NamespaceID,
   213  			*filter.MinTime,
   214  			*filter.MaxTime,
   215  			*filter.RunID,
   216  			*filter.MaxTime,
   217  			*filter.MaxTime,
   218  			*filter.PageSize,
   219  		)
   220  	case filter.MinTime != nil && filter.MaxTime != nil &&
   221  		filter.WorkflowTypeName != nil && filter.RunID != nil && filter.PageSize != nil:
   222  		qry := templateGetOpenWorkflowExecutionsByType
   223  		if filter.Status != 1 {
   224  			qry = templateGetClosedWorkflowExecutionsByType
   225  		}
   226  		err = mdb.conn.SelectContext(ctx,
   227  			&rows,
   228  			qry,
   229  			*filter.WorkflowTypeName,
   230  			filter.NamespaceID,
   231  			*filter.MinTime,
   232  			*filter.MaxTime,
   233  			*filter.RunID,
   234  			*filter.MaxTime,
   235  			*filter.MaxTime,
   236  			*filter.PageSize,
   237  		)
   238  	case filter.MinTime != nil && filter.MaxTime != nil &&
   239  		filter.RunID != nil && filter.PageSize != nil &&
   240  		filter.Status != 0 && filter.Status != 1: // 0 is UNSPECIFIED, 1 is RUNNING
   241  		err = mdb.conn.SelectContext(ctx,
   242  			&rows,
   243  			templateGetClosedWorkflowExecutionsByStatus,
   244  			filter.Status,
   245  			filter.NamespaceID,
   246  			*filter.MinTime,
   247  			*filter.MaxTime,
   248  			*filter.RunID,
   249  			*filter.MaxTime,
   250  			*filter.MaxTime,
   251  			*filter.PageSize,
   252  		)
   253  	case filter.MinTime != nil && filter.MaxTime != nil &&
   254  		filter.RunID != nil && filter.PageSize != nil:
   255  		qry := templateGetOpenWorkflowExecutions
   256  		if filter.Status != 1 {
   257  			qry = templateGetClosedWorkflowExecutions
   258  		}
   259  		err = mdb.conn.SelectContext(ctx,
   260  			&rows,
   261  			qry,
   262  			filter.NamespaceID,
   263  			*filter.MinTime,
   264  			*filter.MaxTime,
   265  			*filter.RunID,
   266  			*filter.MaxTime,
   267  			*filter.MaxTime,
   268  			*filter.PageSize,
   269  		)
   270  	default:
   271  		return nil, fmt.Errorf("invalid query filter")
   272  	}
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	for i := range rows {
   277  		mdb.processRowFromDB(&rows[i])
   278  	}
   279  	return rows, nil
   280  }
   281  
   282  // GetFromVisibility reads one row from visibility table
   283  func (mdb *db) GetFromVisibility(
   284  	ctx context.Context,
   285  	filter sqlplugin.VisibilityGetFilter,
   286  ) (*sqlplugin.VisibilityRow, error) {
   287  	var row sqlplugin.VisibilityRow
   288  	err := mdb.conn.GetContext(ctx,
   289  		&row,
   290  		templateGetWorkflowExecution,
   291  		filter.NamespaceID,
   292  		filter.RunID,
   293  	)
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  	mdb.processRowFromDB(&row)
   298  	return &row, nil
   299  }
   300  
   301  func (mdb *db) CountFromVisibility(
   302  	ctx context.Context,
   303  	filter sqlplugin.VisibilitySelectFilter,
   304  ) (int64, error) {
   305  	return 0, store.OperationNotSupportedErr
   306  }
   307  
   308  func (mdb *db) CountGroupByFromVisibility(
   309  	ctx context.Context,
   310  	filter sqlplugin.VisibilitySelectFilter,
   311  ) ([]sqlplugin.VisibilityCountRow, error) {
   312  	return nil, store.OperationNotSupportedErr
   313  }
   314  
   315  func (mdb *db) processRowFromDB(row *sqlplugin.VisibilityRow) {
   316  	row.StartTime = mdb.converter.FromMySQLDateTime(row.StartTime)
   317  	row.ExecutionTime = mdb.converter.FromMySQLDateTime(row.ExecutionTime)
   318  	if row.CloseTime != nil {
   319  		closeTime := mdb.converter.FromMySQLDateTime(*row.CloseTime)
   320  		row.CloseTime = &closeTime
   321  	}
   322  }