From 4257712eac13619bc7e25fbf183a39496ddaf7ce Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sun, 30 Nov 2025 08:18:52 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 15 + README.md | 3 + commands/stored-proc.md | 511 ++++++++++++++++++ plugin.lock.json | 61 +++ skills/stored-procedure-generator/SKILL.md | 55 ++ .../assets/README.md | 6 + .../references/README.md | 9 + .../scripts/README.md | 7 + 8 files changed, 667 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 commands/stored-proc.md create mode 100644 plugin.lock.json create mode 100644 skills/stored-procedure-generator/SKILL.md create mode 100644 skills/stored-procedure-generator/assets/README.md create mode 100644 skills/stored-procedure-generator/references/README.md create mode 100644 skills/stored-procedure-generator/scripts/README.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..2070b48 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "stored-procedure-generator", + "description": "Database plugin for stored-procedure-generator", + "version": "1.0.0", + "author": { + "name": "Claude Code Plugins", + "email": "[email protected]" + }, + "skills": [ + "./skills" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..456f365 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# stored-procedure-generator + +Database plugin for stored-procedure-generator diff --git a/commands/stored-proc.md b/commands/stored-proc.md new file mode 100644 index 0000000..6089b0e --- /dev/null +++ b/commands/stored-proc.md @@ -0,0 +1,511 @@ +--- +description: Generate production-ready stored procedures and database functions +shortcut: stored-proc +--- + +# Stored Procedure Generator + +Generate production-ready stored procedures, functions, triggers, and custom database logic for complex business rules, performance optimization, and transaction safety across PostgreSQL, MySQL, and SQL Server. + +## When to Use This Command + +Use `/stored-proc` when you need to: +- Implement complex business logic close to the data +- Enforce data integrity constraints beyond foreign keys +- Optimize performance by reducing network round trips +- Implement atomic multi-step operations with transaction safety +- Create reusable database functions for reporting and analytics +- Build database triggers for audit logging and data synchronization + +DON'T use this when: +- Business logic frequently changes (better in application layer) +- Logic requires external API calls or file I/O +- Team lacks database development expertise +- Migrating between database systems (vendor lock-in risk) +- Simple CRUD operations sufficient (ORMs handle this) + +## Design Decisions + +This command implements **comprehensive stored procedure generation** because: +- Encapsulates business logic at database level for data integrity +- Reduces network latency by executing multiple queries in single call +- Provides transaction safety for complex multi-step operations +- Enables code reuse across multiple applications +- Leverages database-specific optimizations (compiled execution plans) + +**Alternative considered: Application-layer logic** +- More portable across database systems +- Easier to test and debug +- Better for frequently changing logic +- Recommended for API-heavy applications + +**Alternative considered: Database views** +- Read-only, no data modification +- Cannot contain procedural logic +- Better query optimizer hints +- Recommended for read-heavy reporting + +## Prerequisites + +Before running this command: +1. Understanding of target database's procedural language (PL/pgSQL, MySQL, T-SQL) +2. Knowledge of business logic requirements and edge cases +3. Database permissions to create procedures/functions +4. Testing framework for stored procedure validation +5. Documentation of expected inputs/outputs and error handling + +## Implementation Process + +### Step 1: Analyze Business Logic Requirements +Define inputs, outputs, error conditions, and transaction boundaries. + +### Step 2: Choose Procedure Type +Select function (returns value), procedure (performs action), or trigger (automated). + +### Step 3: Implement Core Logic +Write procedural code with proper error handling and transaction management. + +### Step 4: Add Validation and Security +Implement input validation, SQL injection prevention, and permission checks. + +### Step 5: Test and Optimize +Test edge cases, measure performance, and optimize execution plans. + +## Output Format + +The command generates: +- `procedures/business_logic.sql` - Production-ready stored procedures +- `functions/calculations.sql` - Reusable database functions +- `triggers/audit_triggers.sql` - Automated data tracking triggers +- `tests/procedure_tests.sql` - Unit tests for validation +- `docs/procedure_api.md` - Documentation with usage examples + +## Code Examples + +### Example 1: PostgreSQL Complex Business Logic Function + +```sql +-- Order processing with inventory management and audit logging +CREATE OR REPLACE FUNCTION process_order( + p_customer_id INTEGER, + p_order_items JSONB, + p_shipping_address JSONB +) RETURNS TABLE ( + order_id INTEGER, + total_amount DECIMAL(10,2), + status VARCHAR(50), + estimated_delivery DATE +) AS $$ +DECLARE + v_order_id INTEGER; + v_total DECIMAL(10,2) := 0; + v_item JSONB; + v_product_id INTEGER; + v_quantity INTEGER; + v_price DECIMAL(10,2); + v_available_stock INTEGER; +BEGIN + -- Validate customer exists and is active + IF NOT EXISTS ( + SELECT 1 FROM customers + WHERE customer_id = p_customer_id AND status = 'active' + ) THEN + RAISE EXCEPTION 'Customer % not found or inactive', p_customer_id + USING HINT = 'Check customer_id and status'; + END IF; + + -- Create order record + INSERT INTO orders (customer_id, order_date, status, shipping_address) + VALUES ( + p_customer_id, + CURRENT_TIMESTAMP, + 'pending', + p_shipping_address + ) + RETURNING order_id INTO v_order_id; + + -- Process each order item + FOR v_item IN SELECT * FROM jsonb_array_elements(p_order_items) + LOOP + v_product_id := (v_item->>'product_id')::INTEGER; + v_quantity := (v_item->>'quantity')::INTEGER; + + -- Validate product exists + SELECT price INTO v_price + FROM products + WHERE product_id = v_product_id AND active = true; + + IF v_price IS NULL THEN + RAISE EXCEPTION 'Product % not found or inactive', v_product_id; + END IF; + + -- Check inventory availability + SELECT stock_quantity INTO v_available_stock + FROM inventory + WHERE product_id = v_product_id + FOR UPDATE; -- Lock row for update + + IF v_available_stock < v_quantity THEN + RAISE EXCEPTION 'Insufficient stock for product %. Available: %, Requested: %', + v_product_id, v_available_stock, v_quantity + USING HINT = 'Reduce quantity or remove from order'; + END IF; + + -- Create order item + INSERT INTO order_items (order_id, product_id, quantity, unit_price, subtotal) + VALUES ( + v_order_id, + v_product_id, + v_quantity, + v_price, + v_quantity * v_price + ); + + -- Update inventory + UPDATE inventory + SET stock_quantity = stock_quantity - v_quantity, + last_updated = CURRENT_TIMESTAMP + WHERE product_id = v_product_id; + + -- Add to total + v_total := v_total + (v_quantity * v_price); + END LOOP; + + -- Update order total + UPDATE orders + SET total_amount = v_total, + status = 'confirmed' + WHERE order_id = v_order_id; + + -- Calculate estimated delivery (3-5 business days) + DECLARE + v_delivery_date DATE; + BEGIN + v_delivery_date := CURRENT_DATE + INTERVAL '3 days'; + + -- Skip weekends + WHILE EXTRACT(DOW FROM v_delivery_date) IN (0, 6) LOOP + v_delivery_date := v_delivery_date + INTERVAL '1 day'; + END LOOP; + END; + + -- Log audit trail + INSERT INTO order_audit_log (order_id, action, user_id, timestamp, details) + VALUES ( + v_order_id, + 'order_created', + CURRENT_USER, + CURRENT_TIMESTAMP, + jsonb_build_object( + 'customer_id', p_customer_id, + 'total_amount', v_total, + 'item_count', jsonb_array_length(p_order_items) + ) + ); + + -- Return order details + RETURN QUERY + SELECT + v_order_id, + v_total, + 'confirmed'::VARCHAR(50), + v_delivery_date; + +EXCEPTION + WHEN OTHERS THEN + -- Log error + INSERT INTO error_log (function_name, error_message, error_detail, timestamp) + VALUES ( + 'process_order', + SQLERRM, + SQLSTATE, + CURRENT_TIMESTAMP + ); + + -- Re-raise exception + RAISE; +END; +$$ LANGUAGE plpgsql; + +-- Usage example +SELECT * FROM process_order( + 123, -- customer_id + '[ + {"product_id": 456, "quantity": 2}, + {"product_id": 789, "quantity": 1} + ]'::JSONB, + '{"street": "123 Main St", "city": "Portland", "state": "OR", "zip": "97201"}'::JSONB +); +``` + +### Example 2: MySQL Stored Procedure with Cursors and Error Handling + +```sql +-- User activity report generator with aggregations +DELIMITER $$ + +CREATE PROCEDURE generate_user_activity_report( + IN p_start_date DATE, + IN p_end_date DATE, + IN p_user_type VARCHAR(50) +) +BEGIN + DECLARE v_user_id INT; + DECLARE v_username VARCHAR(255); + DECLARE v_total_logins INT; + DECLARE v_total_transactions DECIMAL(10,2); + DECLARE v_done INT DEFAULT FALSE; + + -- Cursor to iterate over users + DECLARE user_cursor CURSOR FOR + SELECT user_id, username + FROM users + WHERE user_type = p_user_type + AND created_at <= p_end_date + ORDER BY username; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done = TRUE; + + -- Create temporary results table + DROP TEMPORARY TABLE IF EXISTS temp_user_report; + CREATE TEMPORARY TABLE temp_user_report ( + user_id INT, + username VARCHAR(255), + total_logins INT, + total_transactions DECIMAL(10,2), + avg_transaction_value DECIMAL(10,2), + last_activity_date DATETIME, + activity_status VARCHAR(20) + ); + + -- Start transaction + START TRANSACTION; + + -- Open cursor + OPEN user_cursor; + + user_loop: LOOP + FETCH user_cursor INTO v_user_id, v_username; + + IF v_done THEN + LEAVE user_loop; + END IF; + + -- Count login attempts + SELECT COUNT(*) INTO v_total_logins + FROM login_history + WHERE user_id = v_user_id + AND login_date BETWEEN p_start_date AND p_end_date + AND status = 'success'; + + -- Sum transaction amounts + SELECT COALESCE(SUM(amount), 0) INTO v_total_transactions + FROM transactions + WHERE user_id = v_user_id + AND transaction_date BETWEEN p_start_date AND p_end_date + AND status = 'completed'; + + -- Insert aggregated data + INSERT INTO temp_user_report ( + user_id, + username, + total_logins, + total_transactions, + avg_transaction_value, + last_activity_date, + activity_status + ) + SELECT + v_user_id, + v_username, + v_total_logins, + v_total_transactions, + CASE + WHEN v_total_logins > 0 THEN v_total_transactions / v_total_logins + ELSE 0 + END, + (SELECT MAX(activity_date) + FROM ( + SELECT MAX(login_date) AS activity_date FROM login_history WHERE user_id = v_user_id + UNION ALL + SELECT MAX(transaction_date) FROM transactions WHERE user_id = v_user_id + ) activities), + CASE + WHEN v_total_logins >= 20 THEN 'highly_active' + WHEN v_total_logins >= 5 THEN 'active' + WHEN v_total_logins > 0 THEN 'low_activity' + ELSE 'inactive' + END; + + END LOOP; + + CLOSE user_cursor; + + -- Commit transaction + COMMIT; + + -- Return final report + SELECT + user_id, + username, + total_logins, + FORMAT(total_transactions, 2) AS total_transactions, + FORMAT(avg_transaction_value, 2) AS avg_transaction_value, + DATE_FORMAT(last_activity_date, '%Y-%m-%d %H:%i:%s') AS last_activity, + activity_status + FROM temp_user_report + ORDER BY total_transactions DESC; + +END$$ + +DELIMITER ; + +-- Usage +CALL generate_user_activity_report('2024-01-01', '2024-12-31', 'premium'); +``` + +### Example 3: Database Triggers for Audit Logging + +```sql +-- PostgreSQL audit trigger for tracking all table changes +CREATE OR REPLACE FUNCTION audit_trigger_function() +RETURNS TRIGGER AS $$ +BEGIN + IF TG_OP = 'INSERT' THEN + INSERT INTO audit_log ( + table_name, + operation, + row_id, + new_data, + changed_by, + changed_at + ) VALUES ( + TG_TABLE_NAME, + 'INSERT', + NEW.id, + row_to_json(NEW), + CURRENT_USER, + CURRENT_TIMESTAMP + ); + RETURN NEW; + + ELSIF TG_OP = 'UPDATE' THEN + INSERT INTO audit_log ( + table_name, + operation, + row_id, + old_data, + new_data, + changed_by, + changed_at + ) VALUES ( + TG_TABLE_NAME, + 'UPDATE', + NEW.id, + row_to_json(OLD), + row_to_json(NEW), + CURRENT_USER, + CURRENT_TIMESTAMP + ); + RETURN NEW; + + ELSIF TG_OP = 'DELETE' THEN + INSERT INTO audit_log ( + table_name, + operation, + row_id, + old_data, + changed_by, + changed_at + ) VALUES ( + TG_TABLE_NAME, + 'DELETE', + OLD.id, + row_to_json(OLD), + CURRENT_USER, + CURRENT_TIMESTAMP + ); + RETURN OLD; + END IF; +END; +$$ LANGUAGE plpgsql; + +-- Apply audit trigger to sensitive tables +CREATE TRIGGER users_audit_trigger + AFTER INSERT OR UPDATE OR DELETE ON users + FOR EACH ROW EXECUTE FUNCTION audit_trigger_function(); + +CREATE TRIGGER orders_audit_trigger + AFTER INSERT OR UPDATE OR DELETE ON orders + FOR EACH ROW EXECUTE FUNCTION audit_trigger_function(); + +CREATE TRIGGER transactions_audit_trigger + AFTER INSERT OR UPDATE OR DELETE ON transactions + FOR EACH ROW EXECUTE FUNCTION audit_trigger_function(); +``` + +## Error Handling + +| Error | Cause | Solution | +|-------|-------|----------| +| "Function does not exist" | Missing or misspelled function name | Check function signature and schema | +| "Deadlock detected" | Concurrent transactions locking same rows | Use `FOR UPDATE SKIP LOCKED` or retry logic | +| "Stack depth limit exceeded" | Infinite recursion in function | Add recursion depth limit checks | +| "Out of shared memory" | Too many cursors or temp tables | Close cursors explicitly, limit temp table size | +| "Division by zero" | Unhandled edge case | Add NULL/zero checks before calculations | + +## Configuration Options + +**Function Types** +- **RETURNS TABLE**: Multi-row result sets +- **RETURNS SETOF**: Dynamic result sets +- **RETURNS VOID**: No return value (procedures) +- **RETURNS TRIGGER**: Trigger functions + +**Volatility Categories** +- `IMMUTABLE`: Pure function, same inputs = same outputs +- `STABLE`: Results consistent within transaction +- `VOLATILE`: May change even with same inputs (default) + +**Security Options** +- `SECURITY DEFINER`: Runs with creator's permissions +- `SECURITY INVOKER`: Runs with caller's permissions (default) + +## Best Practices + +DO: +- Use explicit parameter names (p_customer_id, not just id) +- Handle all possible error conditions with meaningful messages +- Use transactions for multi-step operations +- Close cursors explicitly to free resources +- Add input validation at function start +- Document parameters and return values + +DON'T: +- Use `SELECT *` in production functions (specify columns) +- Perform network I/O or file operations in functions +- Create overly complex logic (split into multiple functions) +- Ignore SQL injection risks in dynamic SQL +- Forget to handle NULL values +- Use SECURITY DEFINER without careful permission checks + +## Performance Considerations + +- Functions add ~1-5ms overhead per call (acceptable for complex logic) +- Cached execution plans provide 10-50% speedup on repeated calls +- Triggers add overhead to every INSERT/UPDATE/DELETE (use sparingly) +- Use `FOR UPDATE SKIP LOCKED` to avoid blocking in high-concurrency scenarios +- Avoid cursors when set-based operations possible (cursors 10-100x slower) +- Index columns used in function WHERE clauses + +## Related Commands + +- `/database-migration-manager` - Deploy stored procedures across environments +- `/sql-query-optimizer` - Optimize queries within procedures +- `/database-transaction-monitor` - Monitor procedure execution and locks +- `/database-security-scanner` - Audit procedure permissions and SQL injection risks + +## Version History + +- v1.0.0 (2024-10): Initial implementation with PostgreSQL, MySQL, SQL Server support +- Planned v1.1.0: Add automated procedure testing framework and performance profiling diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..1c8ee52 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,61 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:jeremylongshore/claude-code-plugins-plus:plugins/database/stored-procedure-generator", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "709ed386d082b2ebb665f5124004dd83f070210e", + "treeHash": "a7b0aa64c35e6a215be0c59b623c86234bc61028585057afa824cba9078a5acf", + "generatedAt": "2025-11-28T10:18:47.729585Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "stored-procedure-generator", + "description": "Database plugin for stored-procedure-generator", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "780d13ef96116467bc0fcbb6bce9a1330595568a19d8f7ee2bfb2ca3b857b293" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "5122e602f7cee06711c713cc5bb608160a8e0aade321bd352c73ef53204e8e88" + }, + { + "path": "commands/stored-proc.md", + "sha256": "3c69a0387cc020cd5922f220432c46fb311c5d9d022c00300f4ebe15ca28207d" + }, + { + "path": "skills/stored-procedure-generator/SKILL.md", + "sha256": "d7399354387a661ba7bd6d87ee434d0490fcaaff1cc7b9c2506e25f4e373f2e4" + }, + { + "path": "skills/stored-procedure-generator/references/README.md", + "sha256": "0ec158901e7f764e70864245b1c4ae9a338aac26636ba5dec5cdb7153d4c3fe9" + }, + { + "path": "skills/stored-procedure-generator/scripts/README.md", + "sha256": "48817726fa3ec52362eb257037b7d1bb114e36238cb05e00de82b6cb68a7b5cd" + }, + { + "path": "skills/stored-procedure-generator/assets/README.md", + "sha256": "9a2c625223a66f8233d4980b7fcbaa5be1af78affc12d644704045742cef7a34" + } + ], + "dirSha256": "a7b0aa64c35e6a215be0c59b623c86234bc61028585057afa824cba9078a5acf" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/stored-procedure-generator/SKILL.md b/skills/stored-procedure-generator/SKILL.md new file mode 100644 index 0000000..175a5a9 --- /dev/null +++ b/skills/stored-procedure-generator/SKILL.md @@ -0,0 +1,55 @@ +--- +name: generating-stored-procedures +description: | + This skill uses the stored-procedure-generator plugin to create production-ready stored procedures, functions, triggers, and custom database logic. It supports PostgreSQL, MySQL, and SQL Server. Use this skill when the user asks to "generate stored procedure", "create database function", "write a trigger", or needs help with "database logic", "optimizing database performance", or "ensuring transaction safety" in their database. The skill is activated by requests related to database stored procedures, functions, or triggers. +allowed-tools: Read, Write, Edit, Grep, Glob, Bash +version: 1.0.0 +--- + +## Overview + +This skill empowers Claude to generate efficient, production-ready stored procedures, functions, and triggers for various database systems. It helps implement complex business logic, enforce data integrity, and optimize database performance directly within the database. + +## How It Works + +1. **Identify Requirements**: Claude analyzes the user's request to understand the desired functionality, database system, and any specific constraints. +2. **Generate Code**: Claude uses the stored-procedure-generator plugin to create the appropriate SQL code for the stored procedure, function, or trigger. +3. **Present Code**: Claude presents the generated SQL code to the user for review and deployment. + +## When to Use This Skill + +This skill activates when you need to: +- Implement complex business rules within a database. +- Enforce data integrity constraints beyond simple foreign keys. +- Optimize database performance by minimizing network round trips. +- Implement atomic transactions for data consistency. + +## Examples + +### Example 1: Generating a Stored Procedure for Order Processing + +User request: "generate stored procedure to process orders in PostgreSQL" + +The skill will: +1. Analyze the request and determine the need for a PostgreSQL stored procedure for order processing. +2. Generate the SQL code for a stored procedure that handles order creation, validation, and updates. +3. Present the generated SQL code to the user. + +### Example 2: Creating a Trigger for Auditing Data Changes + +User request: "create a trigger in MySQL to audit changes to the 'products' table" + +The skill will: +1. Analyze the request and determine the need for a MySQL trigger on the 'products' table. +2. Generate the SQL code for a trigger that logs changes (inserts, updates, deletes) to a separate audit table. +3. Present the generated SQL code to the user. + +## Best Practices + +- **Database Choice**: Specify the target database (PostgreSQL, MySQL, SQL Server) for optimal code generation. +- **Detailed Requirements**: Provide clear and detailed requirements for the stored procedure, function, or trigger to ensure accurate code generation. +- **Security Considerations**: Review the generated code for potential security vulnerabilities, such as SQL injection, before deployment. + +## Integration + +This skill can be integrated with other plugins for tasks such as database schema analysis or deployment automation, allowing for a complete end-to-end database development workflow. \ No newline at end of file diff --git a/skills/stored-procedure-generator/assets/README.md b/skills/stored-procedure-generator/assets/README.md new file mode 100644 index 0000000..ab86e11 --- /dev/null +++ b/skills/stored-procedure-generator/assets/README.md @@ -0,0 +1,6 @@ +# Assets + +Bundled resources for stored-procedure-generator skill + +- [ ] stored_procedure_template.sql: A template for generating stored procedures with placeholders for database-specific syntax. +- [ ] example_stored_procedures/: A directory containing example stored procedures for different use cases (e.g., data validation, reporting, user management) for each supported database. diff --git a/skills/stored-procedure-generator/references/README.md b/skills/stored-procedure-generator/references/README.md new file mode 100644 index 0000000..da48b6a --- /dev/null +++ b/skills/stored-procedure-generator/references/README.md @@ -0,0 +1,9 @@ +# References + +Bundled resources for stored-procedure-generator skill + +- [ ] postgresql_stored_procedure_best_practices.md: Best practices for writing stored procedures in PostgreSQL. +- [ ] mysql_stored_procedure_best_practices.md: Best practices for writing stored procedures in MySQL. +- [ ] sqlserver_stored_procedure_best_practices.md: Best practices for writing stored procedures in SQL Server. +- [ ] database_security_guidelines.md: Guidelines for ensuring database security when using stored procedures. +- [ ] stored_procedure_optimization_techniques.md: Techniques for optimizing the performance of stored procedures. diff --git a/skills/stored-procedure-generator/scripts/README.md b/skills/stored-procedure-generator/scripts/README.md new file mode 100644 index 0000000..2ca22bc --- /dev/null +++ b/skills/stored-procedure-generator/scripts/README.md @@ -0,0 +1,7 @@ +# Scripts + +Bundled resources for stored-procedure-generator skill + +- [ ] database_connection_test.py: Tests the database connection using provided credentials and outputs the connection status. +- [ ] stored_procedure_syntax_validator.py: Validates the syntax of the generated stored procedure against the target database (PostgreSQL, MySQL, SQL Server). +- [ ] stored_procedure_deployer.py: Deploys the generated stored procedure to the target database.