From 775c349dac45605cfab5306b35fb4cee3347d704 Mon Sep 17 00:00:00 2001 From: Masayuki Nii Date: Sat, 25 Nov 2023 09:52:38 +0900 Subject: [PATCH] Refactoring, also Schema Generator recognized db-engnine. --- .github/{workflows => keep}/e2e-test-edge.yml | 0 params.php | 3 +- samples/Sample_invoice/include_PostgreSQL.php | 4 +-- .../Sample_invoice/invoice_PostgreSQL.html | 5 +++ src/php/DB/Generator.php | 29 ++++++++++++----- src/php/DB/Proxy.php | 28 ++++++++++------- src/php/DB/Support/DB_PDO_Handler.php | 17 +++++----- src/php/DB/Support/DB_PDO_MySQL_Handler.php | 24 ++++++++++++++ .../DB/Support/DB_PDO_PostgreSQL_Handler.php | 31 +++++++++++++++++++ 9 files changed, 109 insertions(+), 32 deletions(-) rename .github/{workflows => keep}/e2e-test-edge.yml (100%) diff --git a/.github/workflows/e2e-test-edge.yml b/.github/keep/e2e-test-edge.yml similarity index 100% rename from .github/workflows/e2e-test-edge.yml rename to .github/keep/e2e-test-edge.yml diff --git a/params.php b/params.php index 34342eded..d23897b65 100644 --- a/params.php +++ b/params.php @@ -39,7 +39,8 @@ // In case of MySQL, the following account is convenient for generating schema. //$dbUser = 'root'; //$dbPassword = ''; -//$dbDSN = 'mysql:host=127.0.0.1;dbname=test_db2;charset=utf8mb4'; +//$dbDSN = 'mysql:host=127.0.0.1;dbname=test_db3;charset=utf8mb4'; +//$dbDSN = 'pgsql:host=localhost;port=5432;dbname=test_db4'; // The generated db user is going to replace below. //$dbUser = 'webuser'; //$dbPassword = ' 'PDO', - 'dsn' => 'pgsql:host=localhost;port=5432;dbname=test_db', + 'dsn' => 'pgsql:host=localhost;port=5432;dbname=test_db3', ), - false + 2 ); diff --git a/samples/Sample_invoice/invoice_PostgreSQL.html b/samples/Sample_invoice/invoice_PostgreSQL.html index 81bfc0513..2f718ed4b 100755 --- a/samples/Sample_invoice/invoice_PostgreSQL.html +++ b/samples/Sample_invoice/invoice_PostgreSQL.html @@ -17,6 +17,11 @@ INTER-Mediator - Sample - Client-Side Calculation/PostgreSQL +
diff --git a/src/php/DB/Generator.php b/src/php/DB/Generator.php index e188f9b65..b6fd5b465 100644 --- a/src/php/DB/Generator.php +++ b/src/php/DB/Generator.php @@ -65,6 +65,8 @@ class Generator */ private ?array $options; + private array $supportDB = ["mysql",/* "pgsql" */]; + /** * @param Proxy $proxy */ @@ -234,7 +236,7 @@ public function generate(): void public function prepareDatabase(): void { try { // Establishing the connection with database - $this->link = new \PDO($this->generateDSN(), $this->generatorUser, $this->generatorPassword, []); + $this->link = new \PDO($this->generateDSN(true), $this->generatorUser, $this->generatorPassword, []); if (!in_array($this->dsnElements['dbname'], $this->getDatabases())) { $dbName = $this->dsnElements['dbname']; $userName = "webuser"; @@ -242,10 +244,8 @@ public function prepareDatabase(): void $password = str_replace("'", "z", IMUtil::randomString(20)); $sql = $this->proxy->dbClass->handler->sqlCREATEDATABASECommand($dbName); $sql .= $this->proxy->dbClass->handler->sqlCREATEUSERCommand($dbName, $userEntity, $password); - // Can't use $this->proxy->dbClass->handler here, because it's before initializing dbClass property. - //$sql = "CREATE DATABASE {$this->dsnElements['dbname']};"; $this->logger->setDebugMessage("[Schema Generator] Execute SQL:\n{$sql}", 2); - $result = $this->link->query($sql); + $result = $this->link->exec($sql); if (!$result) { throw (new \Exception("Failed in creating database.")); } @@ -266,15 +266,16 @@ private function getDatabases(): array { $dbs = []; try { - $sql = "SHOW DATABASES;"; + $sql = $this->proxy->dbClass->handler->sqlLISTDATABASECommand(); + $field = $this->proxy->dbClass->handler->sqlLISTDATABASEColumn(); $this->logger->setDebugMessage("[Schema Generator] {$sql}"); $result = $this->link->query($sql); if ($result) { foreach ($result->fetchAll(\PDO::FETCH_ASSOC) as $row) { - $dbs[] = $row['Database']; + $dbs[] = $row[$field]; } } - //$this->logger->setDebugMessage("[Schema Generator] " . var_export($dbs, true), 2); + $this->logger->setDebugMessage("[Schema Generator] " . var_export($dbs, true), 2); } catch (PDOException $ex) { $this->logger->setErrorMessage('[Schema Generator] Connection Error: ' . $ex->getMessage()); } @@ -304,9 +305,15 @@ private function parseDSN($dsn): void /** * @return string + * @throws \Exception */ - public function generateDSN(): string + public function generateDSN($withInitDB = false): string { + if(!in_array($this->dsnPrefix, $this->supportDB)){ + $msg = "The database '{$this->dsnPrefix}' is NOT supported for Automatic Schema Generation."; + $this->logger->setWarningMessage($msg); + throw new \Exception($msg); + } $dsn = ''; if (isset($this->dsnElements['unix_socket'])) { $dsn = "{$this->dsnPrefix}:unix_socket={$this->dsnElements['unix_socket']}"; @@ -316,6 +323,12 @@ public function generateDSN(): string $dsn .= ";port={$this->dsnElements['port']}"; } } + if ($withInitDB && $this->dsnPrefix == 'pgsql') { + $initDB = Params::getParameterValue('dbInitalDBName', null); + if ($initDB) { + $dsn .= ";dbname={$initDB}"; + } + } return $dsn; } diff --git a/src/php/DB/Proxy.php b/src/php/DB/Proxy.php index 448a7dcf6..1598bc519 100644 --- a/src/php/DB/Proxy.php +++ b/src/php/DB/Proxy.php @@ -799,25 +799,29 @@ function initialize(?array $datasource, ?array $options, ?array $dbspec, ?int $d $this->dbClass->setUpSharedObjects($this); if ($isDBClassNull) { if ($this->activateGenerator) { // In case of Generator activated - $originalDSN = $this->dbSettings->getDbSpecDSN(); - $generator = new Generator($this); - $this->dbSettings->setDbSpecDSN($generator->generateDSN()); - if (!$this->dbClass->setupConnection()) { // Connection without dbname - return false; - } - $this->dbClass->setupHandlers(); - $generator->prepareDatabase(); // If the database doesn't exist, it's going to create here. - $this->dbSettings->setDbSpecDSN($originalDSN); - if (!$this->dbClass->setupConnection()) { // Recreating database connection + try { + $originalDSN = $this->dbSettings->getDbSpecDSN(); + $this->logger->setDebugMessage("[Schema Generator]originalDSN " . var_export($originalDSN, true), 2); + $generator = new Generator($this); + $this->dbSettings->setDbSpecDSN($generator->generateDSN(true)); + if (!$this->dbClass->setupConnection()) { // Connection without dbname + return false; + } + $this->dbClass->setupHandlers(); + $generator->prepareDatabase(); // If the database doesn't exist, it's going to create here. + $this->dbSettings->setDbSpecDSN($originalDSN); + if (!$this->dbClass->setupConnection()) { // Recreating database connection + return false; + } + } catch (Exception $ex) { // Catching the exception within Generator class. return false; } - $this->dbClass->setupHandlers(); } else { // Here is normal operations for Database Class. if (!$this->dbClass->setupConnection()) { return false; } - $this->dbClass->setupHandlers(); } + $this->dbClass->setupHandlers(); } if (!Params::getParameterValue('prohibitDebugMode', false) && $debug) { $this->logger->setDebugMode($debug); diff --git a/src/php/DB/Support/DB_PDO_Handler.php b/src/php/DB/Support/DB_PDO_Handler.php index 1718f6e21..9359edb61 100644 --- a/src/php/DB/Support/DB_PDO_Handler.php +++ b/src/php/DB/Support/DB_PDO_Handler.php @@ -141,6 +141,13 @@ public abstract function sqlUPDATECommand(): string; */ public abstract function sqlINSERTCommand(string $tableRef, string $setClause): string; + public abstract function sqlLISTDATABASECommand(): string; + + /** + * @return string The field name for database name in the result of database list + */ + public abstract function sqlLISTDATABASEColumn(): string; + /** * @param string $tableRef * @param string $setClause @@ -196,15 +203,7 @@ public function sqlSELECTDATABASECommand(string $dbName): string return "USE {$this->quotedEntityName($dbName)};\n"; } - public function sqlCREATEUSERCommand(string $dbName, string $userEntity, string $password): string - { - $quotedDB = $this->quotedEntityName($dbName); - $quotedUser = $this->quotedData($userEntity, "@"); - $quotedPassword = $this->dbClassObj->link->quote($password); - return "CREATE USER IF NOT EXISTS {$quotedUser};\n" - . "GRANT SELECT, INSERT, DELETE, UPDATE, SHOW VIEW ON TABLE {$quotedDB}.* TO {$quotedUser};\n" - . "SET PASSWORD FOR {$quotedUser} = {$quotedPassword};\n"; - } + public abstract function sqlCREATEUSERCommand(string $dbName, string $userEntity, string $password): string; /** * @param string $data diff --git a/src/php/DB/Support/DB_PDO_MySQL_Handler.php b/src/php/DB/Support/DB_PDO_MySQL_Handler.php index 2f653d2f6..be124ee66 100644 --- a/src/php/DB/Support/DB_PDO_MySQL_Handler.php +++ b/src/php/DB/Support/DB_PDO_MySQL_Handler.php @@ -417,4 +417,28 @@ public function getLastInsertId(string $seqObject): ?string } return null; } + + public function sqlCREATEUSERCommand(string $dbName, string $userEntity, string $password): string + { + $quotedDB = $this->quotedEntityName($dbName); + $quotedUser = $this->quotedData($userEntity, "@"); + $quotedPassword = $this->dbClassObj->link->quote($password); + return "CREATE USER IF NOT EXISTS {$quotedUser};\n" + . "GRANT SELECT, INSERT, DELETE, UPDATE, SHOW VIEW ON TABLE {$quotedDB}.* TO {$quotedUser};\n" + . "SET PASSWORD FOR {$quotedUser} = {$quotedPassword};\n"; + } + + /** + * @return string SQL command returns database list + */ + public function sqlLISTDATABASECommand(): string{ + return "SHOW DATABASES;"; + } + + /** + * @return string The field name for database name in the result of database list + */ + public function sqlLISTDATABASEColumn(): string{ + return "Database"; + } } diff --git a/src/php/DB/Support/DB_PDO_PostgreSQL_Handler.php b/src/php/DB/Support/DB_PDO_PostgreSQL_Handler.php index e99ce48f7..e1ea8f1e7 100644 --- a/src/php/DB/Support/DB_PDO_PostgreSQL_Handler.php +++ b/src/php/DB/Support/DB_PDO_PostgreSQL_Handler.php @@ -355,4 +355,35 @@ public function getSQLNumericToLikeOpe($field, $value): string { return "CAST({$field} AS TEXT) LIKE {$value}"; } + + public function sqlCREATEUSERCommand(string $dbName, string $userEntity, string $password): string + { + $quotedDB = $this->quotedEntityName($dbName); + $justUsername = explode("@", $userEntity)[0]; + $quotedPassword = $this->dbClassObj->link->quote($password); + return + // "CREATE USER {$justUsername} PASSWORD {$quotedPassword};\n". + "DROP SCHEMA IF EXISTS {$quotedDB} CASCADE;" + . "CREATE SCHEMA {$quotedDB};" + . "SET search_path TO {$quotedDB},public;" + . "ALTER USER web SET search_path TO {$quotedDB},public;" + . "GRANT ALL PRIVILEGES ON SCHEMA {$quotedDB} TO {$justUsername};"; + } + + /** + * @return string SQL command returns database list + */ + public function sqlLISTDATABASECommand(): string + { + return "SELECT datname, datdba, encoding, datcollate, datctype FROM pg_database;"; + } + + /** + * @return string The field name for database name in the result of database list + */ + public function sqlLISTDATABASEColumn(): string + { + return "datname"; + } + }