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 }