Stored Procedures: JavaScript, Python & Transaction Management

Free Lesson

Advertisement

Stored Procedures: JavaScript, Python & Transaction Management

Architecture Diagram 1: Stored Procedure Execution Model

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    STORED PROCEDURE EXECUTION MODEL                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  CLIENT APPLICATION                                                         β”‚
β”‚  ══════════════════                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  CALL my_procedure('param1', 'param2');                             β”‚   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Client Driver                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  1. Parse procedure call                                β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  2. Serialize parameters                                β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  3. Send to Snowflake                                   β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                    β”‚                                        β”‚
β”‚                                    β–Ό                                        β”‚
β”‚  SNOWFLAKE CLOUD SERVICES                                                    β”‚
β”‚  ════════════════════════                                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Query Processing Service                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  1. Validate procedure exists and user has EXECUTE privilege  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  2. Parse procedure body (JavaScript/Python/SQL)             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  3. Check for parameter type mismatches                      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  4. Assign virtual warehouse for execution                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  5. Route to appropriate compute cluster                     β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                    β”‚                                        β”‚
β”‚                                    β–Ό                                        β”‚
β”‚  VIRTUAL WAREHOUSE (Compute)                                                β”‚
β”‚  ════════════════════════════                                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  JavaScript Runtime Environment                              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  // JavaScript Procedure Execution                     β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  var sql = snowflake.createStatement({                 β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚    sqlText: "SELECT * FROM table1",                    β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚    binds: [param1, param2]                              β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  });                                                   β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  var result = sql.execute();                            β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  while (result.next()) {                                β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚    // Process each row                                  β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  }                                                      β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  # Python Runtime Environment                           β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  # Uses Snowpark for DataFrame operations               β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  from snowflake.snowpark import Session                 β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  session = Session.builder.configs({...}).create()      β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  df = session.table("table1")                           β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  result = df.filter(col("id") > 10).collect()          β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Transaction Manager                                         β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  BEGIN TRANSACTION;                                     β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  β”œβ”€β”€ SQL Statement 1 ──▢ Result Set                    β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  β”œβ”€β”€ SQL Statement 2 ──▢ Result Set                    β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  β”œβ”€β”€ SQL Statement 3 ──▢ Error ──▢ ROLLBACK            β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”‚  └── COMMIT (if all succeed)                            β”‚  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                    β”‚                                        β”‚
β”‚                                    β–Ό                                        β”‚
β”‚  RESULT SET                                                                 β”‚
β”‚  ═══════════                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Return Value:                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Single value (scalar)                                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Result set (table)                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Both (scalar + result set)                                β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ NULL (no return)                                          β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Architecture Diagram 2: Transaction Management Flow

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TRANSACTION MANAGEMENT FLOW                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  SCENARIO: ETL Process with Multiple Operations                             β”‚
β”‚  ═══════════════════════════════════════════════                             β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  PROCEDURE: load_daily_sales()                                       β”‚   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  Step 1: BEGIN TRANSACTION                                          β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: ACTIVE                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations tracked: 0                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks acquired: None                                         β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                    β”‚                                β”‚   β”‚
β”‚  β”‚                                    β–Ό                                β”‚   β”‚
β”‚  β”‚  Step 2: INSERT INTO staging_sales (100,000 rows)                  β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: ACTIVE                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations tracked: 1                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Rows affected: 100,000                                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks: INSERT lock on staging_sales                         β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                    β”‚                                β”‚   β”‚
β”‚  β”‚                                    β–Ό                                β”‚   β”‚
β”‚  β”‚  Step 3: UPDATE sales_fact SET ... FROM staging_sales             β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: ACTIVE                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations tracked: 2                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Rows affected: 50,000 (matched) + 30,000 (inserted)        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks: UPDATE lock on sales_fact                            β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                    β”‚                                β”‚   β”‚
β”‚  β”‚                                    β–Ό                                β”‚   β”‚
β”‚  β”‚  Step 4: INSERT INTO audit_log (transaction details)              β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: ACTIVE                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations tracked: 3                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Rows affected: 1                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks: INSERT lock on audit_log                             β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                    β”‚                                β”‚   β”‚
β”‚  β”‚                                    β–Ό                                β”‚   β”‚
β”‚  β”‚  Step 5: COMMIT                                                   β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: COMMITTED                                            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations committed: 3                                      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  All changes made permanent                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks released                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Visible to other transactions                                β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β”‚  ERROR SCENARIO:                                                            β”‚
β”‚  ═══════════════                                                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  Step 3: UPDATE fails (constraint violation)                        β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: FAILED                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Error: Duplicate key violation                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Operations tracked: 2                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Rows affected by Step 2: NOT YET VISIBLE                   β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                    β”‚                                β”‚   β”‚
β”‚  β”‚                                    β–Ό                                β”‚   β”‚
β”‚  β”‚  ROLLBACK executed                                                  β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  State: ROLLED BACK                                          β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  All operations undone                                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  100,000 rows inserted in Step 2: REVERTED                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Table restored to pre-transaction state                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Locks released                                               β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β”‚  ISOLATION LEVELS:                                                          β”‚
β”‚  ═════════════════                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  READ COMMITTED (Default):                                          β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Sees only committed data from other transactions          β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Each statement sees snapshot at statement start            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Non-repeatable reads possible                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Phantom reads possible                                    β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  SNAPSHOT ISOLATION:                                                 β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Sees snapshot at transaction start                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Consistent reads throughout transaction                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ No non-repeatable reads                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ No phantom reads                                          β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Architecture Diagram 3: Error Handling Patterns

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ERROR HANDLING PATTERNS                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  PATTERN 1: Basic Error Handling                                            β”‚
β”‚  ═══════════════════════════════                                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  BEGIN                                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    -- Main logic                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    INSERT INTO target_table SELECT * FROM source_table;       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  EXCEPTION                                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHEN OTHER THEN                                            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Log error                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      INSERT INTO error_log (error_message, timestamp)        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      VALUES (:sqlerrm, CURRENT_TIMESTAMP());                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Re-raise error                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      RAISE;                                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  END;                                                         β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β”‚  PATTERN 2: Specific Error Handling                                         β”‚
β”‚  ═════════════════════════════════                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  BEGIN                                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    -- Main logic                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    COPY INTO target_table FROM @stage;                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  EXCEPTION                                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHEN EXPRESSION_ERROR THEN                                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Handle data type errors                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      RETURN 'Data type mismatch';                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHEN SQL_NOT_FOUND THEN                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Handle table not found                                β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      RETURN 'Table does not exist';                           β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHEN NULL_VALUE_NOT_ALLOWED THEN                           β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Handle null constraint violations                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      RETURN 'Null value not allowed';                         β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHEN OTHER THEN                                            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      -- Handle all other errors                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      RETURN 'Unexpected error: ' || :sqlerrm;                β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  END;                                                         β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β”‚  PATTERN 3: Retry Logic with Exponential Backoff                           β”‚
β”‚  ═══════════════════════════════════════════════                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                                                                      β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  DECLARE                                                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    retry_count INTEGER DEFAULT 0;                              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    max_retries INTEGER DEFAULT 3;                              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    wait_time INTEGER DEFAULT 1000; -- milliseconds             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  BEGIN                                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    WHILE (retry_count < max_retries) DO                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      BEGIN                                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚        -- Attempt operation                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚        INSERT INTO target_table SELECT * FROM source_table;   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚        RETURN 'Success';                                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      EXCEPTION                                                β”‚   β”‚   β”‚
β”‚  β”‚  β”‚        WHEN OTHER THEN                                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚          retry_count := retry_count + 1;                      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚          IF (retry_count < max_retries) THEN                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚            -- Exponential backoff                              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚            CALL SYSTEM$WAIT(wait_time);                       β”‚   β”‚   β”‚
β”‚  β”‚  β”‚            wait_time := wait_time * 2;                        β”‚   β”‚   β”‚
β”‚  β”‚  β”‚          END IF;                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚      END;                                                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    END WHILE;                                                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚    RETURN 'Failed after ' || max_retries || ' retries';      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  END;                                                         β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

A stored procedure is a named object containing SQL and procedural code (JavaScript, Python, SQL) that can be executed on-demand. It encapsulates complex business logic, data validation, and multi-step operations into reusable units callable from applications, tasks, or other procedures.

Transaction isolation controls how concurrent transactions interact. Snowflake uses READ COMMITTED by default (each statement sees committed data at statement start). SNAPSHOT isolation provides consistent reads throughout a transaction, preventing non-repeatable reads and phantom reads.

Keep procedures focused on single responsibilities. Always include EXCEPTION blocks with specific error handling. Use transactions for multi-step operations to ensure atomicity. Minimize SQL statements β€” use set-based operations over row-by-row processing.

  • Languages: JavaScript (ETL/validation), Python/Snowpark (data science), SQL (simple logic)
  • Transactions: BEGIN β†’ execute operations β†’ COMMIT (or ROLLBACK on error)
  • Error handling: EXCEPTION blocks with specific error types for targeted recovery
  • Retry logic: Exponential backoff for transient failures
  • Performance: SQL procedures fastest, JavaScript moderate, Python best for complex data processing

Detailed Explanation

Stored Procedure Fundamentals

Snowflake stored procedures are named objects containing SQL and procedural code that can be executed on-demand. They support multiple languages including JavaScript, Python (via Snowpark), and SQL. Stored procedures enable encapsulation of complex business logic, data validation, and multi-step operations into reusable units that can be called from applications, tasks, or other procedures.

The execution model follows a client-server architecture. When a procedure is called, the client sends the procedure name and parameters to Snowflake's cloud services layer. The services layer validates permissions, parses the procedure body, and routes execution to an assigned virtual warehouse. The warehouse executes the procedural code, which can include SQL statements, loops, conditionals, and error handling.

JavaScript Stored Procedures

JavaScript procedures use Snowflake's built-in JavaScript runtime, which provides a familiar syntax for web developers. The runtime includes the snowflake object for executing SQL statements, resultSet objects for processing query results, and standard JavaScript features like variables, loops, and functions.

JavaScript procedures are particularly effective for ETL operations, data validation, and complex data transformations. They can execute multiple SQL statements, process results procedurally, and implement business logic that would be difficult or impossible in pure SQL. The snowflake.createStatement() method creates SQL statements with parameter binding, while execute() runs them and returns result sets.

Python Stored Procedures (Snowpark)

Python procedures leverage the Snowpark library, which provides a DataFrame API for data manipulation. Snowpark enables Python developers to write data processing logic using familiar pandas-like syntax while executing entirely within Snowflake. This eliminates the need to extract data for processing in external Python environments.

Snowpark procedures can use the full Python ecosystem, including NumPy, pandas, scikit-learn, and custom libraries. The Session object provides connection management and DataFrame operations, while session.table() creates DataFrames from existing tables. Snowpark automatically optimizes DataFrame operations and translates them into efficient SQL execution plans.

Transaction Management

Snowflake supports transaction management within stored procedures using BEGIN, COMMIT, and ROLLBACK statements. Transactions ensure that multiple operations execute atomicallyβ€”all succeed or all fail. This is critical for data consistency in ETL processes, where partial updates could leave data in an inconsistent state.

Transaction isolation levels control how concurrent transactions interact. Snowflake uses READ COMMITTED isolation by default, where each statement sees only committed data from other transactions. SNAPSHOT isolation provides consistent reads throughout a transaction, preventing non-repeatable reads and phantom reads.

Error Handling Patterns

Robust stored procedures require comprehensive error handling to manage unexpected conditions gracefully. Snowflake provides EXCEPTION blocks that catch errors and execute recovery logic. Specific exception types (EXPRESSION_ERROR, SQL_NOT_FOUND, NULL_VALUE_NOT_ALLOWED) enable targeted handling for different failure modes.

Common error handling patterns include logging errors to audit tables, retrying transient failures with exponential backoff, and returning meaningful error messages to callers. The RAISE statement re-throws caught exceptions, while RETURN exits the procedure with a status value.

Key Concepts Table

FeatureJavaScriptPython (Snowpark)SQL
Execution ModelInterpreterInterpreterCompiled
Data AccessSQL statementsDataFramesDirect SQL
Library SupportLimitedFull Python ecosystemNone
PerformanceGoodExcellent (optimized)Best
Use CaseETL, validationData science, MLSimple logic
Transaction OperationSyntaxDescription
BEGINBEGIN TRANSACTIONStart transaction
COMMITCOMMITSave all changes
ROLLBACKROLLBACKUndo all changes
SAVEPOINTSAVEPOINT sp1Create checkpoint
ROLLBACK TOROLLBACK TO sp1Restore to checkpoint
Exception TypeCommon CauseTypical Response
EXPRESSION_ERRORType mismatchValidate input types
SQL_NOT_FOUNDMissing objectCheck object existence
NULL_VALUE_NOT_ALLOWEDConstraint violationHandle NULLs explicitly
DUPLICATE_KEYUnique constraintUpdate or skip duplicates

Code Examples

-- Example 1: Basic JavaScript procedure
CREATE OR REPLACE PROCEDURE get_customer_stats(customer_id VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
    var sql = `SELECT COUNT(*) as order_count, 
                      SUM(amount) as total_amount
               FROM orders 
               WHERE customer_id = '${customer_id}'`;
    
    var stmt = snowflake.createStatement({sqlText: sql});
    var result = stmt.execute();
    
    if (result.next()) {
        return `Orders: ${result.getColumnValue(1)}, ` +
               `Total: $${result.getColumnValue(2)}`;
    }
    return 'No data found';
$$;

-- Example 2: JavaScript procedure with transaction
CREATE OR REPLACE PROCEDURE transfer_funds(
    from_account VARCHAR,
    to_account VARCHAR,
    amount NUMBER
)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
    try {
        // Begin transaction
        snowflake.createStatement({sqlText: "BEGIN TRANSACTION"}).execute();
        
        // Debit source account
        snowflake.createStatement({
            sqlText: `UPDATE accounts SET balance = balance - ${amount} 
                      WHERE account_id = '${from_account}'`
        }).execute();
        
        // Credit destination account
        snowflake.createStatement({
            sqlText: `UPDATE accounts SET balance = balance + ${amount} 
                      WHERE account_id = '${to_account}'`
        }).execute();
        
        // Commit transaction
        snowflake.createStatement({sqlText: "COMMIT"}).execute();
        
        return 'Transfer successful';
    } catch (err) {
        // Rollback on error
        snowflake.createStatement({sqlText: "ROLLBACK"}).execute();
        return 'Transfer failed: ' + err.message;
    }
$$;

-- Example 3: Python procedure with Snowpark
CREATE OR REPLACE PROCEDURE process_data_snowpark()
RETURNS VARIANT
LANGUAGE PYTHON
RUNTIME_VERSION = '3.8'
PACKAGES = ('snowflake-snowpark-python')
HANDLER = 'main'
AS
$$
from snowflake.snowpark import Session
from snowflake.snowpark.functions import col, sum as sum_, count

def main(session: Session):
    # Read data
    df = session.table("raw_data")
    
    # Transform data
    result = df.filter(col("status") == "active") \
               .group_by("category") \
               .agg(
                   count("*").alias("record_count"),
                   sum_(col("amount")).alias("total_amount")
               ) \
               .collect()
    
    # Write results
    session.create_dataframe(result).write.mode("overwrite") \
        .save_as_table("processed_data")
    
    return {"status": "success", "rows_processed": len(result)}
$$;

-- Example 4: SQL procedure with error handling
CREATE OR REPLACE PROCEDURE safe_insert(
    table_name VARCHAR,
    data VARIANT
)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
DECLARE
    error_msg VARCHAR;
BEGIN
    -- Attempt insert
    INSERT INTO IDENTIFIER(table_name) 
    SELECT * FROM TABLE(FLATTEN(input => :data));
    
    RETURN 'Insert successful';
    
EXCEPTION
    WHEN EXPRESSION_ERROR THEN
        RETURN 'Data type mismatch error';
    WHEN OTHER THEN
        error_msg := SQLERRM;
        INSERT INTO error_log (procedure_name, error_message, timestamp)
        VALUES ('safe_insert', :error_msg, CURRENT_TIMESTAMP());
        RETURN 'Insert failed: ' || :error_msg;
END;
$$;

-- Example 5: Procedure with retry logic
CREATE OR REPLACE PROCEDURE retry_operation(
    operation_sql VARCHAR,
    max_retries INTEGER DEFAULT 3
)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
DECLARE
    retry_count INTEGER DEFAULT 0;
    wait_time INTEGER DEFAULT 1000;
    result VARCHAR;
BEGIN
    WHILE (retry_count < max_retries) DO
        BEGIN
            -- Execute operation
            EXECUTE IMMEDIATE :operation_sql;
            RETURN 'Operation successful';
            
        EXCEPTION
            WHEN OTHER THEN
                retry_count := retry_count + 1;
                IF (retry_count < max_retries) THEN
                    -- Exponential backoff
                    CALL SYSTEM$WAIT(:wait_time);
                    wait_time := wait_time * 2;
                END IF;
        END;
    END WHILE;
    
    RETURN 'Operation failed after ' || :max_retries || ' retries';
END;
$$;

-- Example 6: Call procedure
CALL get_customer_stats('CUST-001');
CALL transfer_funds('ACC-001', 'ACC-002', 1000.00);
CALL process_data_snowpark();
CALL safe_insert('target_table', PARSE_JSON('[{"id": 1, "name": "test"}]'));

Performance Metrics

MetricTargetWarningCritical
Procedure Execution Time< 30s30-120s> 120s
SQL Statement Count< 1010-50> 50
Transaction Duration< 60s60-300s> 300s
Error Rate< 1%1-5%> 5%
Retry Success Rate> 90%70-90%< 70%

Best Practices

  1. Keep procedures focused: Design each procedure for a single responsibility. Avoid monolithic procedures that handle multiple unrelated tasks.

  2. Implement comprehensive error handling: Always include EXCEPTION blocks with specific error handling. Log errors for debugging and monitoring.

  3. Use transactions for consistency: Wrap multi-step operations in transactions to ensure atomicity. Use SAVEPOINTs for partial rollback scenarios.

  4. Validate input parameters: Check parameter types and values at procedure start. Return meaningful errors for invalid inputs.

  5. Minimize SQL statements: Reduce the number of SQL statements within procedures. Use set-based operations instead of row-by-row processing.

  6. Use appropriate language: Choose JavaScript for ETL and validation, Python for data science and ML, SQL for simple business logic.

  7. Implement retry logic: Add retry mechanisms for transient failures. Use exponential backoff to avoid overwhelming systems.

  8. Document procedures: Include comments explaining purpose, parameters, and return values. Maintain procedure documentation separately.

  9. Test thoroughly: Test procedures with various inputs, including edge cases and error conditions. Verify transaction behavior.

  10. Monitor performance: Track execution times, SQL statement counts, and error rates. Optimize slow procedures based on metrics.


See Also

Advertisement

Need Expert Snowflake Help?

Get personalized warehouse optimization, data modeling, or Snowflake platform consulting.

Advertisement