Files
michaelschiemer/tests/debug/test-table-partitioning.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

269 lines
11 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../../src/Framework/Database/Schema/SchemaCompiler.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Blueprint.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/PartitionType.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Partition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ColumnDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/IndexDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/IndexType.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ForeignKeyDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ForeignKeyAction.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/PostgreSQLSchemaCompiler.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Commands/CreateTableCommand.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Commands/DropTableCommand.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Commands/RawCommand.php';
use App\Framework\Database\Schema\Blueprint;
use App\Framework\Database\Schema\PartitionType;
use App\Framework\Database\Schema\Partition;
use App\Framework\Database\Schema\PostgreSQLSchemaCompiler;
use App\Framework\Database\Schema\Commands\CreateTableCommand;
use App\Framework\Database\Schema\Commands\DropTableCommand;
echo "Testing PostgreSQL Table Partitioning\n";
echo "======================================\n\n";
try {
$pdo = new PDO(
'pgsql:host=db;dbname=michaelschiemer',
'postgres',
'StartSimple2024!'
);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "✅ Database connection established\n\n";
$compiler = new PostgreSQLSchemaCompiler();
// Cleanup
echo "Cleanup...\n";
$pdo->exec("DROP TABLE IF EXISTS sales_2024_q1 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS sales_2024_q2 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS sales_2024 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS customers_eu CASCADE");
$pdo->exec("DROP TABLE IF EXISTS customers_us CASCADE");
$pdo->exec("DROP TABLE IF EXISTS customers_asia CASCADE");
$pdo->exec("DROP TABLE IF EXISTS customers CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders_p0 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders_p1 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders_p2 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders_p3 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders CASCADE");
echo "✅ Cleanup complete\n\n";
// Test 1: RANGE Partitioning (by date)
echo "Test 1: RANGE Partitioning\n";
echo "===========================\n";
$blueprint = new Blueprint('sales_2024');
$blueprint->bigInteger('id'); // Changed from bigIncrements to avoid auto PK
$blueprint->string('product_name');
$blueprint->decimal('amount', 10, 2);
$blueprint->date('sale_date');
$blueprint->primary('id', 'sale_date'); // PK must include partition key
$blueprint->partitionByRange('sale_date');
$createCommand = new CreateTableCommand('sales_2024', $blueprint);
$sql = $compiler->compile($createCommand);
echo "Creating partitioned table:\n";
echo $sql . "\n\n";
$pdo->exec($sql);
echo "✅ Partitioned table 'sales_2024' created\n\n";
// Create partitions
echo "Creating partitions for Q1 and Q2:\n";
$q1Partition = Partition::range('sales_2024_q1', "FOR VALUES FROM ('2024-01-01') TO ('2024-04-01')");
$q1Sql = $q1Partition->toSql('sales_2024');
echo $q1Sql . "\n";
$pdo->exec($q1Sql);
echo "✅ Partition Q1 created\n";
$q2Partition = Partition::range('sales_2024_q2', "FOR VALUES FROM ('2024-04-01') TO ('2024-07-01')");
$q2Sql = $q2Partition->toSql('sales_2024');
echo $q2Sql . "\n";
$pdo->exec($q2Sql);
echo "✅ Partition Q2 created\n\n";
// Insert test data
echo "Inserting test data:\n";
$pdo->exec("
INSERT INTO sales_2024 (id, product_name, amount, sale_date) VALUES
(1, 'Laptop', 1200.00, '2024-02-15'),
(2, 'Mouse', 25.00, '2024-03-10'),
(3, 'Keyboard', 75.00, '2024-05-20')
");
echo "✅ 3 records inserted (2 in Q1, 1 in Q2)\n\n";
// Verify data distribution
echo "Verifying partition data:\n";
$q1Count = $pdo->query("SELECT COUNT(*) FROM sales_2024_q1")->fetchColumn();
$q2Count = $pdo->query("SELECT COUNT(*) FROM sales_2024_q2")->fetchColumn();
echo " - Q1: {$q1Count} records\n";
echo " - Q2: {$q2Count} records\n";
echo ($q1Count == 2 && $q2Count == 1) ? "✅ Data correctly distributed\n\n" : "❌ Wrong distribution\n\n";
// Test 2: LIST Partitioning (by region)
echo "Test 2: LIST Partitioning\n";
echo "==========================\n";
$blueprint = new Blueprint('customers');
$blueprint->bigInteger('id');
$blueprint->string('name');
$blueprint->string('email');
$blueprint->string('region', 10);
$blueprint->primary('id', 'region'); // PK must include partition key
$blueprint->partitionByList('region');
$createCommand = new CreateTableCommand('customers', $blueprint);
$sql = $compiler->compile($createCommand);
echo "Creating list-partitioned table:\n";
echo $sql . "\n\n";
$pdo->exec($sql);
echo "✅ List-partitioned table 'customers' created\n\n";
// Create list partitions
echo "Creating regional partitions:\n";
$euPartition = Partition::list('customers_eu', "FOR VALUES IN ('DE', 'FR', 'IT', 'ES')");
$euSql = $euPartition->toSql('customers');
echo $euSql . "\n";
$pdo->exec($euSql);
echo "✅ EU partition created\n";
$usPartition = Partition::list('customers_us', "FOR VALUES IN ('US', 'CA', 'MX')");
$usSql = $usPartition->toSql('customers');
echo $usSql . "\n";
$pdo->exec($usSql);
echo "✅ US partition created\n";
$asiaPartition = Partition::list('customers_asia', "FOR VALUES IN ('JP', 'CN', 'IN', 'KR')");
$asiaSql = $asiaPartition->toSql('customers');
echo $asiaSql . "\n";
$pdo->exec($asiaSql);
echo "✅ ASIA partition created\n\n";
// Insert test data
echo "Inserting regional customers:\n";
$pdo->exec("
INSERT INTO customers (id, name, email, region) VALUES
(1, 'Hans Mueller', 'hans@example.de', 'DE'),
(2, 'Pierre Dupont', 'pierre@example.fr', 'FR'),
(3, 'John Smith', 'john@example.com', 'US'),
(4, 'Yuki Tanaka', 'yuki@example.jp', 'JP')
");
echo "✅ 4 customers inserted across regions\n\n";
// Verify regional distribution
echo "Verifying regional distribution:\n";
$euCount = $pdo->query("SELECT COUNT(*) FROM customers_eu")->fetchColumn();
$usCount = $pdo->query("SELECT COUNT(*) FROM customers_us")->fetchColumn();
$asiaCount = $pdo->query("SELECT COUNT(*) FROM customers_asia")->fetchColumn();
echo " - EU: {$euCount} customers\n";
echo " - US: {$usCount} customers\n";
echo " - ASIA: {$asiaCount} customers\n";
echo ($euCount == 2 && $usCount == 1 && $asiaCount == 1) ? "✅ Regional distribution correct\n\n" : "❌ Wrong distribution\n\n";
// Test 3: HASH Partitioning (for distributed load)
echo "Test 3: HASH Partitioning\n";
echo "==========================\n";
$blueprint = new Blueprint('orders');
$blueprint->bigInteger('id');
$blueprint->bigInteger('customer_id');
$blueprint->decimal('total', 10, 2);
$blueprint->timestamp('created_at');
$blueprint->primary('id', 'customer_id'); // PK must include partition key
$blueprint->partitionByHash('customer_id');
$createCommand = new CreateTableCommand('orders', $blueprint);
$sql = $compiler->compile($createCommand);
echo "Creating hash-partitioned table:\n";
echo $sql . "\n\n";
$pdo->exec($sql);
echo "✅ Hash-partitioned table 'orders' created\n\n";
// Create hash partitions (4 partitions, modulus 4)
echo "Creating 4 hash partitions:\n";
for ($i = 0; $i < 4; $i++) {
$partition = Partition::hash("orders_p{$i}", "FOR VALUES WITH (MODULUS 4, REMAINDER {$i})");
$partSql = $partition->toSql('orders');
echo $partSql . "\n";
$pdo->exec($partSql);
echo "✅ Partition p{$i} created\n";
}
echo "\n";
// Insert test data
echo "Inserting orders:\n";
for ($orderId = 1; $orderId <= 20; $orderId++) {
$customerId = ($orderId % 10) + 1; // Distribute across 10 customers
$pdo->exec("
INSERT INTO orders (id, customer_id, total, created_at)
VALUES ({$orderId}, {$customerId}, " . ($orderId * 50.00) . ", NOW())
");
}
echo "✅ 20 orders inserted (distributed by hash)\n\n";
// Verify hash distribution
echo "Verifying hash distribution:\n";
for ($i = 0; $i < 4; $i++) {
$count = $pdo->query("SELECT COUNT(*) FROM orders_p{$i}")->fetchColumn();
echo " - Partition p{$i}: {$count} orders\n";
}
$totalOrders = $pdo->query("SELECT COUNT(*) FROM orders")->fetchColumn();
echo ($totalOrders == 20) ? "✅ All orders accessible via parent table\n\n" : "❌ Missing orders\n\n";
// Test 4: Check partition metadata
echo "Test 4: Partition Metadata\n";
echo "===========================\n";
$stmt = $pdo->query("
SELECT
inhrelid::regclass AS partition_name,
inhparent::regclass AS parent_table
FROM pg_inherits
WHERE inhparent::regclass::text IN ('sales_2024', 'customers', 'orders')
ORDER BY parent_table, partition_name
");
$partitions = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "Found " . count($partitions) . " partitions:\n";
foreach ($partitions as $partition) {
echo " - {$partition['partition_name']}{$partition['parent_table']}\n";
}
echo (count($partitions) == 9) ? "\n✅ All partitions registered\n\n" : "\n❌ Wrong partition count\n\n";
// Cleanup
echo "Cleanup...\n";
$pdo->exec("DROP TABLE IF EXISTS sales_2024 CASCADE");
$pdo->exec("DROP TABLE IF EXISTS customers CASCADE");
$pdo->exec("DROP TABLE IF EXISTS orders CASCADE");
echo "✅ Test data cleaned up\n";
echo "\n✅ All Table Partitioning tests passed!\n";
echo "\nSummary:\n";
echo "========\n";
echo "✅ RANGE partitioning works (by date)\n";
echo "✅ LIST partitioning works (by discrete values)\n";
echo "✅ HASH partitioning works (distributed load)\n";
echo "✅ Data correctly routed to partitions\n";
echo "✅ Parent table provides unified access\n";
echo "✅ Partition metadata correctly tracked\n";
} catch (\Exception $e) {
echo "❌ Error: " . $e->getMessage() . "\n";
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
exit(1);
}