{"elements":[{"id":7015,"title":"Multi-DBMS","body":"<section class=\"da-section\">\n  <div class=\"container\">\n    <h2>Supporto Multi-DBMS<\/h2>\n    <p class=\"lead\">DressAPI fornisce un livello di astrazione completo su pi&ugrave; sistemi di gestione database. Il codice applicativo interagisce con il database tramite un'API unificata, mentre i dettagli specifici del DBMS sono incapsulati in classi driver dedicate.<\/p>\n\n    <h3 class=\"mt-4\">Database supportati<\/h3>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Valore DB_TYPE<\/th><th>Estensione PHP<\/th><th>Stato<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL \/ MariaDB<\/td><td><code>MySQL<\/code><\/td><td><code>mysqli<\/code><\/td><td>Produzione<\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td><code>PostgreSQL<\/code><\/td><td><code>pgsql<\/code><\/td><td>Implementato<\/td><\/tr>\n          <tr><td>Oracle<\/td><td><code>Oracle<\/code><\/td><td><code>oci8<\/code><\/td><td>Implementato (richiede Oracle 12c+)<\/td><\/tr>\n          <tr><td>SQL Server<\/td><td><code>MSSQL<\/code> o <code>SqlServer<\/code><\/td><td><code>sqlsrv<\/code><\/td><td>Implementato (richiede SQL Server 2012+)<\/td><\/tr>\n          <tr><td>PDO (multi-backend)<\/td><td><code>PDO<\/code><\/td><td><code>PDO<\/code><\/td><td>Implementato<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h3 class=\"mt-5\">Architettura a 3 livelli<\/h3>\n    <p>Il supporto multi-DBMS &egrave; costruito su tre livelli, ciascuno con responsabilit&agrave; chiare:<\/p>\n    <ul>\n      <li><strong>CDB (Facade)<\/strong> &ndash; Punto di ingresso principale. Accetta un ConnectionManager, crea il driver DBMS corretto tramite <code>CreateDbmsDriver()<\/code>, delega tutte le chiamate IDBMS al driver sottostante e integra il caching.<\/li>\n      <li><strong>ConnectionManager (Pool connessioni)<\/strong> &ndash; Memorizza i parametri di connessione, gestisce un pool di connessioni con nome e implementa le connessioni lazy (differite fino a <code>GetConnection()<\/code>).<\/li>\n      <li><strong>CSqlComposer (Dialetto SQL)<\/strong> &ndash; Gestisce le differenze nella sintassi SQL tra i DBMS. Fornisce un'API fluent builder per costruire query in modo portabile.<\/li>\n    <\/ul>\n    <pre class=\"da-snippet\">Codice Applicativo (Controller, Model)\n        |                |                |\n        v                v                v\n   CDB (Facade)   CSqlComposer     IDBMS (Interface)\n        |            (Factory)           |\n        v                |               v\nConnectionManager   Composer        Driver DBMS\n(IConnectionMgr)   specifico       specifico\n        |                |               |\n        v                v               v\n   Estensioni PHP (mysqli, pgsql, oci8, sqlsrv, PDO)\n        |\n        v\n   Server Database (MySQL, PostgreSQL, Oracle, MSSQL)<\/pre>\n\n    <h3 class=\"mt-5\">Meccanismo di connessione lazy<\/h3>\n    <p>Quando viene chiamato <code>CDB::Connect()<\/code> nel bootstrap, il ConnectionManager <strong>memorizza i parametri ma non apre una connessione TCP<\/strong>. La connessione reale avviene solo quando viene eseguita la prima query (o in caso di cache miss).<\/p>\n    <ol>\n      <li><strong>Connect()<\/strong> memorizza solo i parametri e restituisce una chiave (formato: <code>hostname:porta.database.username<\/code>)<\/li>\n      <li><strong>GetConnection()<\/strong> attiva la connessione lazy chiamando <code>RealConnectionForKey()<\/code><\/li>\n      <li><strong>RealConnectionForKey()<\/strong> apre la connessione TCP effettiva<\/li>\n    <\/ol>\n    <p>Vantaggi: bootstrap pi&ugrave; veloce, efficienza delle risorse, gestione errori contestuale.<\/p>\n    <pre class=\"da-snippet\">\/\/ Connect() memorizza solo i parametri\npublic function Connect(string $dbname, string $username, string $pwd,\n                        string $hostname, int|string $port): mixed\n{\n    $key = $hostname . ':' . $port . '.' . $dbname . '.' . $username;\n    $this-&gt;connection_params[$key] = [\n        'hostname' =&gt; $hostname,\n        'username' =&gt; $username,\n        'password' =&gt; $pwd,\n        'database' =&gt; $dbname,\n        'port'     =&gt; (int)$port\n    ];\n    return $key;  \/\/ Restituisce una chiave, NON un handle di connessione\n}<\/pre>\n\n    <h3 class=\"mt-5\">Costanti di configurazione<\/h3>\n    <p>Definisci queste costanti nel file <code>config.php<\/code> della tua applicazione:<\/p>\n    <pre class=\"da-snippet\">define('DB_TYPE',     'MySQL');      \/\/ MySQL, PostgreSQL, Oracle, MSSQL, SqlServer, PDO\ndefine('DB_HOST',     'localhost');\ndefine('DB_PORT',     3306);         \/\/ MySQL: 3306, PostgreSQL: 5432, Oracle: 1521, MSSQL: 1433\ndefine('DB_NAME',     'my_database');\ndefine('DB_USERNAME', 'db_user');\ndefine('DB_PASSWORD', 'db_password');<\/pre>\n\n    <h3 class=\"mt-5\">Factory Pattern in CSqlComposer<\/h3>\n    <p><code>CSqlComposer<\/code> &egrave; una classe <code>final<\/code> che usa l'espressione <code>match<\/code> di PHP come factory per creare il composer specifico del DBMS:<\/p>\n    <pre class=\"da-snippet\">final class CSqlComposer implements ISqlComposer\n{\n    protected mixed $composer;\n\n    public function __construct(string $dbms_type, ?string $items = '*', ...)\n    {\n        $this-&gt;composer = match($dbms_type)\n        {\n            'mysql'              =&gt; new CMySqlComposer($items, $table, ...),\n            'postgresql'         =&gt; new CPostgreSqlComposer($items, $table, ...),\n            'oracle'             =&gt; new COracleComposer($items, $table, ...),\n            'mssql', 'sqlserver' =&gt; new CMsSqlComposer($items, $table, ...),\n            default              =&gt; throw new InvalidArgumentException(\n                                        \"Unknown DBMS type: $dbms_type\")\n        };\n    }\n}<\/pre>\n    <p>Gerarchia delle classi:<\/p>\n    <pre class=\"da-snippet\">ISqlComposer (interfaccia)\n    |\n    +-- CSqlComposerBase (base astratta - SQL standard)\n    |       +-- CMySqlComposer\n    |       +-- CPostgreSqlComposer\n    |       +-- COracleComposer\n    |       +-- CMsSqlComposer\n    |\n    +-- CSqlComposer (factory\/wrapper finale - delega alle classi sopra)<\/pre>\n\n    <h3 class=\"mt-5\">Mapping tipi specifici per DBMS<\/h3>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>Tipo logico<\/th><th>MySQL<\/th><th>PostgreSQL<\/th><th>Oracle<\/th><th>SQL Server<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>DB_TYPE_ID<\/td><td>INT<\/td><td>SERIAL<\/td><td>NUMBER<\/td><td>INT<\/td><\/tr>\n          <tr><td>DB_TYPE_NAME<\/td><td>VARCHAR<\/td><td>VARCHAR<\/td><td>VARCHAR2<\/td><td>NVARCHAR<\/td><\/tr>\n          <tr><td>DB_TYPE_INT<\/td><td>INT<\/td><td>INTEGER<\/td><td>NUMBER<\/td><td>INT<\/td><\/tr>\n          <tr><td>DB_TYPE_DATE<\/td><td>DATE<\/td><td>DATE<\/td><td>DATE<\/td><td>DATE<\/td><\/tr>\n          <tr><td>DB_TYPE_DATETIME<\/td><td>DATETIME<\/td><td>TIMESTAMP<\/td><td>TIMESTAMP<\/td><td>DATETIME2<\/td><\/tr>\n          <tr><td>DB_TYPE_SET<\/td><td>SET<\/td><td>TEXT[]<\/td><td>VARCHAR2<\/td><td>NVARCHAR<\/td><\/tr>\n          <tr><td>DB_FUNC_NOW<\/td><td>date('Y-m-d H:i:s')<\/td><td>NOW()<\/td><td>SYSDATE<\/td><td>GETDATE()<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h3 class=\"mt-5\">Interfaccia ConnectionManager<\/h3>\n    <p>Ogni DBMS implementa l'interfaccia <code>IConnectionManager<\/code>:<\/p>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>Metodo<\/th><th>Scopo<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td><code>Connect()<\/code><\/td><td>Memorizza i parametri e restituisce una chiave di connessione (NON apre una connessione)<\/td><\/tr>\n          <tr><td><code>GetConnection()<\/code><\/td><td>Restituisce l'handle di connessione, aprendolo in modo lazy se necessario<\/td><\/tr>\n          <tr><td><code>HasConnection()<\/code><\/td><td>Verifica se una connessione esiste (parametri memorizzati O gi&agrave; connesso)<\/td><\/tr>\n          <tr><td><code>RealConnection()<\/code><\/td><td>Forza l'apertura della connessione TCP<\/td><\/tr>\n          <tr><td><code>Disconnect()<\/code><\/td><td>Chiude una connessione specifica<\/td><\/tr>\n          <tr><td><code>DisconnectAll()<\/code><\/td><td>Chiude tutte le connessioni aperte<\/td><\/tr>\n          <tr><td><code>GetDbmsType()<\/code><\/td><td>Restituisce l'identificativo del DBMS (es. <code>mysql<\/code>, <code>postgresql<\/code>)<\/td><\/tr>\n          <tr><td><code>SetAutoCommit()<\/code><\/td><td>Abilita o disabilita l'autocommit su tutte le connessioni<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h3 class=\"mt-5\">API builder SqlComposer<\/h3>\n    <p>L'API fluent consente di costruire query portabili tra DBMS:<\/p>\n    <pre class=\"da-snippet\">$sql = new CSqlComposer('mysql');\n$sql-&gt;Select('id, name, email')\n    -&gt;From('users')\n    -&gt;Where('active = ?', [1], ['i'])\n    -&gt;OrderBy(['name'])\n    -&gt;Paging(1, 20);\n\n$query = $sql-&gt;Prepare();\n\/\/ MySQL:      \"SELECT id, name, email FROM users WHERE (active = ?) ORDER BY name LIMIT 0,20\"\n\/\/ PostgreSQL: \"... LIMIT 20 OFFSET 0\"\n\/\/ Oracle:     \"... OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY\"\n\/\/ SQL Server: \"... OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY\"<\/pre>\n\n    <h3 class=\"mt-5\">Passaggio tra DBMS<\/h3>\n    <p>Basta cambiare la costante <code>DB_TYPE<\/code> nel file <code>config.php<\/code> e tutto il resto si adatta automaticamente:<\/p>\n    <ol>\n      <li>Installa l'estensione PHP richiesta per il DBMS di destinazione<\/li>\n      <li>Aggiorna <code>DB_TYPE<\/code>, <code>DB_HOST<\/code>, <code>DB_PORT<\/code> nel <code>config.php<\/code><\/li>\n      <li>Migra lo schema del database (crea le tabelle framework con la sintassi appropriata)<\/li>\n    <\/ol>\n    <pre class=\"da-snippet\">\/\/ PostgreSQL\ndefine('DB_TYPE', 'PostgreSQL');\ndefine('DB_PORT', 5432);\n\n\/\/ Oracle\ndefine('DB_TYPE', 'Oracle');\ndefine('DB_PORT', 1521);\n\n\/\/ SQL Server\ndefine('DB_TYPE', 'MSSQL');\ndefine('DB_PORT', 1433);<\/pre>\n\n    <h3 class=\"mt-5\">Differenze specifiche per DBMS<\/h3>\n\n    <h4 class=\"mt-4\">Paginazione<\/h4>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Sintassi SQL<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL<\/td><td><code>LIMIT offset, count<\/code><\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td><code>LIMIT count OFFSET offset<\/code><\/td><\/tr>\n          <tr><td>Oracle (12c+)<\/td><td><code>OFFSET n ROWS FETCH NEXT m ROWS ONLY<\/code><\/td><\/tr>\n          <tr><td>SQL Server (2012+)<\/td><td><code>OFFSET n ROWS FETCH NEXT m ROWS ONLY<\/code> (richiede <code>ORDER BY<\/code>)<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h4 class=\"mt-4\">Quoting degli identificatori<\/h4>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Stile<\/th><th>Esempio<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL<\/td><td>Backtick<\/td><td><code>`nome_colonna`<\/code><\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td>Doppi apici<\/td><td><code>&quot;nome_colonna&quot;<\/code><\/td><\/tr>\n          <tr><td>Oracle<\/td><td>Doppi apici<\/td><td><code>&quot;nome_colonna&quot;<\/code><\/td><\/tr>\n          <tr><td>SQL Server<\/td><td>Parentesi quadre<\/td><td><code>[nome_colonna]<\/code><\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h4 class=\"mt-4\">Concatenazione stringhe<\/h4>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Metodo<\/th><th>Sintassi<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL<\/td><td>Funzione CONCAT()<\/td><td><code>CONCAT(a, b, c)<\/code><\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td>Operatore ||<\/td><td><code>a || b || c<\/code><\/td><\/tr>\n          <tr><td>Oracle<\/td><td>Operatore ||<\/td><td><code>a || b || c<\/code><\/td><\/tr>\n          <tr><td>SQL Server<\/td><td>Operatore +<\/td><td><code>a + b + c<\/code><\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h4 class=\"mt-4\">Ricerca full-text<\/h4>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Sintassi<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL<\/td><td><code>MATCH(colonne) AGAINST('testo')<\/code><\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td><code>to_tsvector(colonne) @@ plainto_tsquery('testo')<\/code><\/td><\/tr>\n          <tr><td>Oracle<\/td><td><code>CONTAINS(colonne, 'testo')<\/code> con <code>SCORE()<\/code><\/td><\/tr>\n          <tr><td>SQL Server<\/td><td><code>CONTAINS(colonne, 'testo')<\/code><\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h4 class=\"mt-4\">Sintassi dei placeholder<\/h4>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>DBMS<\/th><th>Stile<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td>MySQL<\/td><td><code>?<\/code> (posizionale)<\/td><\/tr>\n          <tr><td>PostgreSQL<\/td><td><code>$1, $2, $3<\/code> (convertiti da <code>?<\/code>)<\/td><\/tr>\n          <tr><td>Oracle<\/td><td><code>:bind1, :bind2<\/code> (named bind)<\/td><\/tr>\n          <tr><td>SQL Server<\/td><td><code>?<\/code> (posizionale)<\/td><\/tr>\n          <tr><td>PDO<\/td><td><code>?<\/code> (posizionale)<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h3 class=\"mt-5\">Gerarchia delle eccezioni<\/h3>\n    <pre class=\"da-snippet\">Exception\n    |\n    +-- CDbmsException           (base per tutte le eccezioni DBMS)\n            |\n            +-- CConnectionException  (errori di connessione)\n            +-- CQueryException        (errori di esecuzione query, include la stringa SQL)<\/pre>\n    <div class=\"table-responsive\">\n      <table class=\"table table-striped\">\n        <thead class=\"table-dark\">\n          <tr><th>Eccezione<\/th><th>Quando viene lanciata<\/th><th>Dati extra<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          <tr><td><code>CDbmsException<\/code><\/td><td>Classe base per tutti gli errori DB<\/td><td>Campi standard Exception<\/td><\/tr>\n          <tr><td><code>CConnectionException<\/code><\/td><td>Connessione fallita, tipo DBMS non supportato<\/td><td>Messaggio, codice, eccezione precedente<\/td><\/tr>\n          <tr><td><code>CQueryException<\/code><\/td><td>Errore esecuzione SQL<\/td><td><code>GetSql()<\/code> restituisce la query fallita<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <h3 class=\"mt-5\">Riferimento classi e mappa file<\/h3>\n    <p>Tutti i file si trovano in <code>core\/src\/dbms\/<\/code>:<\/p>\n    <pre class=\"da-snippet\">core\/src\/dbms\/\n    Interfacce:\n    +-- IDBMS.php                        # Interfaccia driver DBMS\n    +-- IConnectionManager.php           # Interfaccia pool connessioni\n    +-- ISqlComposer.php                 # Interfaccia SQL builder\n\n    Facade \/ Factory:\n    +-- CDB.php                          # Classe facade principale\n    +-- CSqlComposer.php                 # Factory\/proxy per SQL composer\n    +-- CSqlComposerBase.php             # Base astratta per SQL composer\n\n    MySQL:\n    +-- CMySqlDb.php                     # Driver MySQL (mysqli)\n    +-- CMySqlConnectionManager.php      # Pool connessioni MySQL\n    +-- CMySqlComposer.php               # Dialetto SQL MySQL\n\n    PostgreSQL:\n    +-- CPostgreSqlDb.php                # Driver PostgreSQL (pgsql)\n    +-- CPostgreSqlConnectionManager.php # Pool connessioni PostgreSQL\n    +-- CPostgreSqlComposer.php          # Dialetto SQL PostgreSQL\n\n    Oracle:\n    +-- COracleDb.php                    # Driver Oracle (oci8)\n    +-- COracleConnectionManager.php     # Pool connessioni Oracle\n    +-- COracleComposer.php              # Dialetto SQL Oracle\n\n    SQL Server:\n    +-- CMsSqlDb.php                     # Driver SQL Server (sqlsrv)\n    +-- CMsSqlConnectionManager.php      # Pool connessioni SQL Server\n    +-- CMsSqlComposer.php               # Dialetto SQL SQL Server\n\n    PDO:\n    +-- CPdoDb.php                       # Driver PDO (multi-backend)\n    +-- CPdoConnectionManager.php        # Pool connessioni PDO\n\n    Eccezioni:\n    +-- CDbmsException.php               # Eccezione base DBMS\n    +-- CConnectionException.php         # Eccezione connessione fallita\n    +-- CQueryException.php              # Eccezione esecuzione query<\/pre>\n  <\/div>\n<\/section>\n\n<section class=\"da-section text-center\">\n  <a href=\"\/tutorials\" class=\"btn btn-outline-primary\">&larr; Torna ai Tutorial<\/a>\n<\/section>","description":"Supporto multi-database: MySQL, PostgreSQL, Oracle, SQL Server e PDO. Architettura a 3 livelli, connessione lazy e astrazione SQL.","meta_keywords":"","visible":"yes","status":"public","creation_date":"0000-00-00","id__user":1,"priority":0,"groupname":"TUTORIAL"}],"module":"pages","permissions":{"can_read":true},"main_item_title":"title","related_tables":[{"name":"Newsonpage","module":"newsonpage","FK":"id_cmspage","permissions":[]}],"page_info":{"table":"","key":"id","url":"\/pages","url_list":"\/pages","filters":{"id":["=","7015"]},"pagination":{"total_items":23,"page":1,"total_pages":2,"step":1,"items_per_page":20,"url_prev":"\/pages","url_next":"\/pages\/p\/2","url_tmpl":"\/pages\/p\/[[p]]","url_tmpl_with_order":"\/pages\/p\/[[p]]\/ob\/[[ob]]"},"order":{"field":"id","type":"DESC","url_tmpl":"\/pages\/p\/[[p]]"},"module":{"title":"Pages","description":"List of pages","name":"pages"},"current":{"title":"Pages","description":"List of pages","name":"pages","url":"\/tutorials\/multi-dbms"}},"components":{"alert":{"alert1":[{"type":"warning","message":"OK COMPONENT!"},{"type":"danger","message":"ERROR COMPONENT!"}]}},"messages":[]}