<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mia mamma usa Linux! &#187; Database</title>
	<atom:link href="http://www.miamammausalinux.org/category/database/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.miamammausalinux.org</link>
	<description>Perché niente è impossibile da capire... Se lo spieghi bene !</description>
	<lastBuildDate>Tue, 27 Jul 2010 12:03:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>MySQL Cluster, un database ad alta affidabilità : Parte 3</title>
		<link>http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/</link>
		<comments>http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/#comments</comments>
		<pubDate>Wed, 01 Mar 2006 11:30:15 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Alta affidabilità]]></category>
		<category><![CDATA[MySQL Cluster]]></category>

		<guid isPermaLink="false">http://www.miamammausalinux.org/?p=149</guid>
		<description><![CDATA[In questo terzo ed ultimo articolo completeremo il discorso sul cluster MySQL imparando a consultare i log, a capire le fasi di avvio ed i meccanismi di registrazione. Infine effettueremo il backup ed il restore delle basi dati registrate. Consultare i log Prima di effettuare qualsiasi tipo di operazione per comprendere la gestione dei log, [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/mysql.png" alt="mysql" title="mysql" width="100" class="alignnone size-full wp-image-173" /></p>
<p>In questo terzo ed ultimo articolo completeremo il discorso sul cluster MySQL imparando a consultare i log, a capire le fasi di avvio ed i meccanismi di registrazione. Infine effettueremo il backup ed il restore delle basi dati registrate.</p>
<p><strong>Consultare i log</strong></p>
<p>Prima di effettuare qualsiasi tipo di operazione per comprendere la gestione dei log, è necessario avviare il cluster.<br />
Partendo dal presupposto che tutti i file sono configurati come illustrato negli scorsi numeri, dal management server è necessario lanciare il comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgmd --config-file=/mysql/config.ini</pre></div></div>

<p>E su ciascuno dei nodi dati :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndbd -n</pre></div></div>

<p>L&#8217;opzione “-n”, come già spiegato, inizializza i nodi dati senza avviarli. L&#8217;avvio effettivo dei nodi dati andrà forzato attraverso la shell <em>ndb_mgm</em> e consentirà di controllare attraverso i log le fasi di avvio. Sempre attraverso questa shell, è possibile verificare lo stato attuale del cluster :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm&gt; show
Connected to Management Server at: management.mycluster.local:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @192.168.0.2  (Version: 5.0.12, not started)
id=3    @192.168.0.3  (Version: 5.0.12, not started)
&nbsp;
[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.0.1  (Version: 5.0.12)
&nbsp;
[mysqld(API)]   1 node(s)
id=4 (not connected, accepting connect from any host)</pre></div></div>

<p>Quanto visualizzato, conferma che stiamo operando su di un cluster che comprende due nodi dati (in stato “not started”), un nodo di management ed un nodo client, al momento non connesso.<br />
I nodi dati ed il nodo di management registrano i log nella cartella che è stata dichiarata nella sezione <em>DataDir</em> all&#8217;interno del file <em>config.ini</em> del management server.<br />
Nel nostro caso, la <em>DataDir</em> dei nostri nodi è <em>/mysql/</em>. Al di sotto di questa, su ciascun nodo, si trovano file denominati <em>ndb_ID_out.log</em>, dove “ID” rappresenta l&#8217;identificativo del nodo, quindi ad esempio, il nodo di management scriverà i log all&#8217;interno del file <em>ndb_1_out.log</em>.<br />
Visualizzando il contenuto di questi file, ci si può fare una chiara idea di ciò che i vari nodi stanno facendo.<br />
Partendo dalla macchina di management, il contenuto del file sarà questo :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ tail /mysql/ndb_1_out.log
NDB Cluster Management Server. Version 5.0.12 (beta)
Id: 1, Command port: 1186</pre></div></div>

<p>Questo conferma che il management è stato avviato ed è in ascolto sulla porta 1186.<br />
Sul nodo due, il file conterrà :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ tail /mysql/ndb_2_out.log
2005-10-28 10:10:54 [NDB] INFO     -- Angel pid: 11026 ndb pid: 11027
2005-10-28 10:10:54 [NDB] INFO     -- NDB Cluster -- DB node 2
2005-10-28 10:10:54 [NDB] INFO     -- Version 5.0.12 (beta) --
2005-10-28 10:10:54 [NDB] INFO     -- Configuration fetched at management.mycluster.local port 1186</pre></div></div>

<p>Mentre nel nodo tre, il file avrà questo contenuto :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ tail /mysql/ndb_3_out.log
2005-10-28 10:10:59 [NDB] INFO     -- Angel pid: 11061 ndb pid: 11062
2005-10-28 10:10:59 [NDB] INFO     -- NDB Cluster -- DB node 3
2005-10-28 10:10:59 [NDB] INFO     -- Version 5.0.12 (beta) --
2005-10-28 10:10:59 [NDB] INFO     -- Configuration fetched at management.mycluster.local port 1186</pre></div></div>

<p>In entrambi i casi, abbiamo la conferma che i nodi dati si sono avviati nella maniera corretta e sono collegati al management server tramite la porta 1186.<br />
Da notare come vengano indicati anche i pid (ossia i numeri identificativi) dei DUE processi relativi al nodo dati : quello angelo, che consente il controllo dei processi dalla console remota <em>ndb_mgm</em>, e quello effettivo, che si occupa della gestione dell&#8217;interscambio dati.<br />
Le informazioni relative allo stato generale del cluster sono memorizzate sul management server nel file denominato <em>ndb_1_cluster.log</em>. In questo file vengono registrati tutti gli eventi che riguardano il cluster. Appena avviato ed una volta effettuate le connessioni da parte dei nodi dati e client, il suo contenuto dovrebbe essere simile al seguente :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ tail /mysql/ndb_1_cluster.log
2005-10-28 10:10:47 [MgmSrvr] INFO     -- NDB Cluster Management Server. Version 5.0.12 (beta)
2005-10-28 10:10:47 [MgmSrvr] INFO     -- Id: 1, Command port: 1186
2005-10-28 10:10:54 [MgmSrvr] INFO     -- Mgmt server state: nodeid 2 reserved for ip 192.168.0.2, m_reserved_nodes 0000000000000006.
2005-10-28 10:10:54 [MgmSrvr] INFO     -- Node 1: Node 2 Connected
2005-10-28 10:10:55 [MgmSrvr] INFO     -- Mgmt server state: nodeid 2 freed, m_reserved_nodes 0000000000000002.
2005-10-28 10:10:59 [MgmSrvr] INFO     -- Mgmt server state: nodeid 3 reserved for ip 192.168.0.3, m_reserved_nodes 000000000000000a.
2005-10-28 10:10:59 [MgmSrvr] INFO     -- Node 1: Node 3 Connected
2005-10-28 10:11:00 [MgmSrvr] INFO     -- Mgmt server state: nodeid 3 freed, m_reserved_nodes 0000000000000002.</pre></div></div>

<p>I nodi 2 e 3 sono stati inizializzati e tramite la connessione al management node, hanno ottenuto il proprio “Node ID” e la configurazione del cluster. Questa fase preliminare dell&#8217;avvio dei nodi prevede  l&#8217;allocazione delle porte che verranno usate per la comunicazione inter-nodo ed infine l&#8217;allocazione della memoria in relazione a quanto dichiarato nella configurazione.</p>
<p><strong>Log e Checkpoints</strong></p>
<p>Per studiare le fasi di avvio del cluster attraverso i Log, è necessario comprendere i meccanismi con cui i dati vengono registrati su disco.<br />
MySQL Cluster è un database distribuito su più nodi e le informazioni in esso contenute sono replicate in maniera sincrona. Questo significa che un&#8217;operazione di aggiornamento, definita “transazione”, prima di essere registrata nel database, cioè prima di raggiungere lo stato “commited”, deve essere effettuata sulla replica primaria e su ciascuna delle secondarie.<br />
Anche se il database risiede completamente nella memoria del cluster, è ovvio che ciascun nodo possiede un filesystem nel quale vengono fisicamente memorizzati i dati. Sarebbe altrimenti impossibile recuperare i dati una volta spente le macchine, visto che il contenuto della RAM è svuotato ad ogni avvio del computer. Questo filesystem si trova su ogni nodo nella directory dichiarata come DataDir nel file di configurazione. Ad esempio, per il nodo con id 2, il filesystem verrà memorizzato all&#8217;interno della directory <em>/mysql/ndb_2_fs</em>.<br />
Ciascun nodo, tiene traccia delle transazioni all&#8217;interno del “REDO log”. La funzione del REDO log è quella di fornire un backup in caso l&#8217;intero cluster cada. I log sono controllati in maniera centralizzata, ma vengono effettuati localmente, sul filesystem di ciascun nodo.<br />
Il <em>REDO log</em> è registrato in memoria e ad intervalli regolari (di default ogni 2 secondi) scritto su disco. Ogni volta che il <em>REDO log</em> viene scritto, viene effettuato un “Global Checkpoint” o “GCP” :</p>
<div id="attachment_152" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura1-300x204.png" alt="Figura 1" title="mysql-cluster_articolo_3-10-figura1" width="300" height="204" class="size-medium wp-image-152" /></a><p class="wp-caption-text">Figura 1</p></div>
<p>La frequenza con cui i <em>GCP</em> vengono eseguiti può essere variata all&#8217;interno del file di configurazione del management server, indicando per l&#8217;opzione <em>TimeBetweenGlobalCheckpoints</em> un valore in millisecondi fra 10 e  32000.<br />
Per alleggerire il carico di informazioni registrate nei <em>REDO log</em> (che è un file incrementale e che quindi continua ad ingrandirsi) e consentire una rapida ricostruzione in caso di totale caduta del cluster, MySQL effettua, sempre ad intervalli regolari, dei “Local Checkpoints” o “LCP”.<br />
Durante un <em>LCP</em> viene creata una copia su disco, definita “Snapshot”, di tutto il database e viene alleggerito il <em>Redo Log</em> al quale viene rimossa la coda delle operazioni svolte sino a quel momento :</p>
<div id="attachment_153" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura2.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura2-300x204.png" alt="Figura 2" title="mysql-cluster_articolo_3-10-figura2" width="300" height="204" class="size-medium wp-image-153" /></a><p class="wp-caption-text">Figura 2</p></div>
<p>Un <em>LCP</em> impiega parecchio tempo a completarsi e viene effettuato mentre il database viene aggiornato. Quanto viene scritto quindi, è da considerarsi inconsistente, in quanto potrebbero esserci delle transazioni non concluse, delle tabelle su cui persiste un lock e così via. Per questo motivo, al momento dell&#8217;avvio di un <em>LCP</em>, viene creato un <em>UNDO log</em>, ossia un registro delle operazioni effettuate dal database durante il <em>LCP</em>.<br />
L&#8217;<em>UNDO log</em> consente di rendere lo snapshot del database, una volta terminato il <em>LCP</em>, di nuovo consistente :</p>
<div id="attachment_154" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura3.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2006/03/mysql-cluster_articolo_3-10-figura3-300x204.png" alt="Figura 3" title="mysql-cluster_articolo_3-10-figura3" width="300" height="204" class="size-medium wp-image-154" /></a><p class="wp-caption-text">Figura 3</p></div>
<p>Anche in questo caso la frequenza degli <em>LCP</em> può variare in funzione alle esigenze, settando nel file di configurazione l&#8217;opzione <em>TimeBetweenLocalCheckpoints</em>.<br />
Riassumendo, se un solo nodo per qualsiasi ragione cade, si ricostruirà seguendo queste fasi :</p>
<ul>
<li>Riconnessione al server di management e segnalazione della propria presenza agli altri membri;</li>
<li>Copia dei metadata, ossia tabelle, indici ed informazioni del cluster dal management server;</li>
<li>Copia dei dati dal nodo primario;</li>
<li>Riassunzione dello stato di nodo primario;</li>
</ul>
<p>Se invece sarà tutto il sistema a cadere, allora il database verrà ricostruito partendo dall&#8217;ultimo <em>LCP</em> e dalle parti di <em>REDO Log</em> che sono state registrate su disco dall&#8217;ultimo <em>GCP</em>. Le transazioni registrate DOPO l&#8217;ultimo <em>GCP</em> verranno perse. Questa serie di operazioni è definita “System recovery”.</p>
<p><strong>Le fasi di avvio del Cluster</strong></p>
<p>A questo punto possiamo seguire le fasi di avvio del cluster direttamente dal file di log della macchina di management, lanciando il comando</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ tail -f /mysql/ndb_1_cluster.log</pre></div></div>

<p>e forzando da una nuova shell della macchina di management l&#8217;avvio dei nodi dati tramite il programma <em>ndb_mgm</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm&gt; all start
Connected to Management Server at: management.mycluster.local:1186
NDB Cluster is being started.
NDB Cluster is being started.</pre></div></div>

<p>Nel file di <em>ndb_1_cluster.log</em> si potranno seguire le operazioni preliminari di avvio del cluster :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 2: Start initiated (version 5.0.12)
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 3: Start initiated (version 5.0.12)
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 2: Start phase 0 completed
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 2: Communication to Node 3 opened
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 3: Start phase 0 completed
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 3: Communication to Node 2 opened
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 2: Node 3 Connected
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 3: Node 2 Connected</pre></div></div>

<p>Da questo punto in poi, i nodi attraverseranno le varie fasi che porteranno all&#8217;avvio effettivo del cluster.  Queste, definite stage, sono 12 e partono da 0 :</p>
<ul>
<li>Stage 0 : Se il processo ndbd è stato avviato tramite un “initial start”, cioè con l&#8217;opzione &#8211;initial (si veda l&#8217;articolo precedente), viene pulito il filesystem del nodo relativo.</li>
<li>Stage 1 : E&#8217; la prima vera fase di avvio in cui vengono stabilite le connessioni tra i nodi ed avviati gli heartbeat (letteralmente “battito cardiaco”), ossia i processi di controllo esistenza di ciascun nodo verso gli altri.<br />
Una comunicazione heartbeat prevede uno scambio di messaggi come “Io ci sono. Tu ci sei ?” che consentono ad ogni nodo di decidere come agire in caso di problemi. Ad esempio, una mancata risposta ad un heartbeat  da parte di un nodo primario imporrebbe al nodo contenente la replica secondaria di far diventare la sua copia di dati primaria.</li>
<li>Stage 2 : In questa fase viene eletto il nodo bilanciatore, che può essere o il management node o uno dei nodi sql client. La funzione del nodo bilanciatore sarà quella di decidere come distribuire il carico delle richieste sui nodi dati. </li>
<li>Stage 3 : Vengono inizializzate alcune variabili interne del cluster. </li>
<li>Stage 4 : Se viene forzata la pulitura del filesystem relativo a tutto il cluster o al singolo nodo,  viene creato il “REDO log”.</li>
<li>Stage 5 : In questa fase, un nodo che è stato riavviato (e deve quindi reinserirsi nel cluster)  viene sincronizzato con il nodo master ed incluso nelle transazioni.</li>
<li>Stage 6 e 7 : Viene effettuato l&#8217;aggiornamento di variabili interne.</li>
<li>Stage 8 : Vengono ricostruiti tutti gli indici.</li>
<li>Stage 9 : Viene effettuato l&#8217;aggiornamento di variabili interne.</li>
<li>Stage 10 : Le applicazioni possono connettersi ai nodi ed incominciare ad effettuare interscambio dati.</li>
<li>Stage 11 : Un nodo immesso all&#8217;interno del cluster assume il ruolo di replica primaria ed effettua l&#8217;invio della replica allo slave associato.</li>
</ul>
<p>Il passaggio da una fase all&#8217;altra è segnalato all&#8217;interno dei log con il messaggio “Start phase <numero> completed” :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">...
2005-10-28 11:06:59 [MgmSrvr] INFO     -- Node 2: Start phase 1 completed
...</pre></div></div>

<p>Chiaramente, non avendo ancora collegato un client e non avendo effettuato alcun riavvio, al termine della fase 9 il nostro cluster è avviato :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">...
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 2: Started (version 5.0.12)
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Communication to Node 4 opened
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Communication to Node 5 opened
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Communication to Node 0 opened
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Start phase 8 completed (initial start)
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Start phase 9 completed (initial start)
2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 3: Started (version 5.0.12)
2005-10-28 11:07:06 [MgmSrvr] INFO     -- Node 3: Node 1: API version 5.0.12
2005-10-28 11:07:06 [MgmSrvr] INFO     -- Node 2: Node 1: API version 5.0.12
2005-10-28 11:07:06 [MgmSrvr] INFO     -- Node 3: Prepare arbitrator node 1 [ticket=399a0001367af1d4]
2005-10-28 11:07:06 [MgmSrvr] INFO     -- Node 2: Started arbitrator node 1 [ticket=399a0001367af1d4]</pre></div></div>

<p>E&#8217; da notare come l&#8217;ultimo messaggio indichi chi sia l&#8217;arbitrator node (il bilanciatore del carico), cioè il management server.<br />
A questo punto, per completare l&#8217;avvio del Cluster ed iniziare ad accedere alle tabelle, possiamo avviare il server mysqld che si collegherà al cluster</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ mysqld --defaults-file=/mysql/my.cnf &amp;</pre></div></div>

<p>ed osservare quanto viene scritto nei log :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">2005-10-28 15:57:26 [MgmSrvr] INFO     -- Mgmt server state: nodeid 4 reserved for ip 192.168.0.4, m_reserved_nodes 0000000000000012.
2005-10-28 15:57:27 [MgmSrvr] INFO     -- Node 3: Node 4 Connected
2005-10-28 15:57:27 [MgmSrvr] INFO     -- Node 2: Node 4 Connected
2005-10-28 15:57:27 [MgmSrvr] INFO     -- Node 2: Node 4: API version 5.0.12
2005-10-28 15:57:27 [MgmSrvr] INFO     -- Node 3: Node 4: API version 5.0.12</pre></div></div>

<p>Il client mysqld si è collegato al server di management, ha scaricato la configurazione e si è collegato direttamente ai nodi dati del cluster con cui effettuerà interscambio dati.<br />
Un&#8217;ultima nota riguardo ai log del cluster riguarda l&#8217;esecuzione dei <em>Local Checkpoints</em> che verrà segnalata all&#8217;interno del file <em>/mysql/ndb_1_cluster.log</em> sulla macchina di management con righe simili a quella che segue :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">2005-10-28 11:07:05 [MgmSrvr] INFO     -- Node 2: Local checkpoint 1 started. Keep GCI = 1 oldest restorable GCI = 1</pre></div></div>

<p>Questa riga indica che è stato avviato il <em>LCP</em> con identificativo 1 sul Nodo 2 e che l&#8217;ultimo <em>GCP</em> ripristinabile è quello con identificativo 1.<br />
Ovviamente, mano a mano che passerà il tempo, altre indicazioni di questo tipo seguiranno :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">...
...
2005-10-28 12:01:43 [MgmSrvr] INFO     -- Node 2: Local checkpoint 2 started. Keep GCI = 1 oldest restorable GCI = 2
2005-10-28 12:56:21 [MgmSrvr] INFO     -- Node 2: Local checkpoint 3 started. Keep GCI = 1609 oldest restorable GCI = 3
...
...
2005-11-01 04:16:15 [MgmSrvr] INFO     -- Node 2: Local checkpoint 100 started. Keep GCI = 157530 oldest restorable GCI = 8890
2005-11-01 05:10:53 [MgmSrvr] INFO     -- Node 2: Local checkpoint 101 started. Keep GCI = 159138 oldest restorable GCI = 8890
...
...</pre></div></div>

<p>Come si può osservare, la frequenza tra un <em>Local Checkpoint</em> ed un altro è di circa un ora.</p>
<p><strong>Backup e Restore</strong></p>
<p>Terminata la spiegazione relativa ai log, concludiamo il discorso relativo al Cluster MySQL con le operazioni di Backup e Restore.</p>
<p><em>Backup</em></p>
<p>Effettuare backup periodici di una base dati è essenziale per svariate ragioni : riparare ad errori causati dalle applicazioni, effettuare un aggiornamento del cluster (che non è possibile eseguire in linea) e ripristinare l&#8217;intera base dati in seguito ad un totale crash del sistema.<br />
I metodi di backup sono essenzialmente due : logico e fisico.</p>
<p><em>Backup logici</em> : I backup logici riguardano l&#8217;esportazione della struttura logica del database in file sql. Tali backup possono essere effettuati attraverso gli strumenti canonici di mysql quali ad esempio il programma mysqldump.<br />
Questi si rivelano utili per il trasferimento dell&#8217;intera base dati ad un altro tipo di database, essendo scritti nel linguaggio sql standard, universalmente comprensibile.<br />
Un esempio di come effettuare un backup tramite mysqldump è il seguente :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ mysqldump  ndb_test &gt; ndb_test_BACKUP.sql</pre></div></div>

<p>Questo comando creerà un file denominato <em>ndb_test_BACKUP.sql</em> nella directory corrente che conterrà tutti gli statement sql necessari alla totale ricostruzione del database ndb_test che abbiamo creato nel precedente articolo.<br />
Questo metodo di backup risulta comodo se si ha la necessità di esportare database dalle dimensioni ridotte o semplicemente singole tabelle, ma su basi dati dalle dimensioni sostenute, non risulta una scelta vincente.</p>
<p><em>Backup fisici</em> : I backup fisici riguardano le copie fisiche dei filesystem dei nodi. Questo tipo di backup è realizzabile unicamente attraverso l&#8217;utilizzo degli strumenti offerti dalla suite mysql-max e proprio per questo, su basi dati di grandezza notevole, è più performante di un backup logico.<br />
Per avviare un backup è sufficiente avviare la console di management e digitare il comando “start backup” :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">ndb_mgm&gt; start backup
Waiting for completed, this may take several minutes
Node 2: Backup 1 started from node 1
Node 2: Backup 1 started from node 1 completed
StartGCP: 300415 StopGCP: 300418
 #Records: 4098 #LogRecords: 0
 Data: 65688 bytes Log: 0 bytes</pre></div></div>

<p>Quanto visualizzato, conferma la corretta esecuzione del backup : nella directory /mysql di ciascun nodo, è stata creata una sottodirectory denominata BACKUP che conterrà a sua volta tante sottodirectory quanti saranno i backup che effettueremo. Per il nodo 2 ad esempio, questa sarà la struttura delle directory :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ pwd
/mysql/BACKUP/BACKUP-1
$ ls
BACKUP-1-0.2.Data  BACKUP-1.2.ctl  BACKUP-1.2.log</pre></div></div>

<p>I file creati sono tre. Questo perché la struttura dei backup <em>MySQL Cluster</em> è composta da tre parti : i metadata (ossia le informazioni sulla struttura del database), i dati delle tabelle ed il log relativo alle transazioni.<br />
I tre file creati hanno quindi le seguenti corrispondenze :</p>
<ul>
<li>BACKUP-<id del backup>.<id del nodo>.ctl contenente i metadata;</li>
<li>BACKUP-<id del backup>-<id del file>.<id del nodo>.Data contenente i metadata;</li>
<li>BACKUP-<id del backup>.<id del nodo>.log contenente i log delle transazioni;</li>
</ul>
<p><strong>Restore</strong></p>
<p>Per effettuare il restore di backup logici è sufficiente eseguire gli statement sql presenti nel file creato con il comando mysqldump.<br />
Discorso a parte va fatto per i backup fisici, il cui restore si può effettuare solo tramite l&#8217;utilizzo del programma <em>ndb_restore</em>.<br />
Anche se il backup è stato effettuato in maniera centralizzata, ossia attraverso la console di management, i file di backup effettivi risiedono su ciascun nodo, pertanto il restore va lanciato tante volte quanti sono i nodi dati presenti nel cluster.<br />
Per prima cosa quindi, considerando come le tabelle che verranno ripristinate non dovranno esistere, è necessario rimuoverle dal database di test creato nello scorso articolo :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ mysql
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 1 to server version: 5.0.12-beta-max
&nbsp;
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
&nbsp;
mysql&gt; drop table ndb_test.test;
Query OK, 1 row affected (0.22 sec)
&nbsp;
mysql&gt; quit
Bye</pre></div></div>

<p>Successivamente, va considerato che il programma <em>ndb_restore</em> agisce come un nodo sql e per connettersi al server di management necessita di un node id disponibile.<br />
La configurazione del cluster a cui il management node fa riferimento prevede la connessione di un solo nodo client, che quindi non deve essere occupato dal server <em>mysqld</em>. Prima di lanciare le operazioni di backup è necessario stoppare dalla macchina di management il server mysqld, ad esempio in questo modo :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ pkill mysqld</pre></div></div>

<p>a questo punto è possibile avviare il test di restore recandosi sul nodo 2 e lanciando questo comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_restore --connect=&quot;nodeid=4;host=management.mycluster.local:1186&quot; --nodeid=2 --backupid=1 --restore_meta --restore_data /mysql/BACKUP/BACKUP-1/
Ndb version in backup files: Version 5.0.12
Connected to ndb!!
Successfully restored table ndb_test/def/test
_____________________________________________________
Processing data in table: ndb_test/def/test(2) fragment 0
_____________________________________________________
Processing data in table: sys/def/NDB$EVENTS_0(1) fragment 0
_____________________________________________________
Processing data in table: sys/def/SYSTAB_0(0) fragment 0
Restored 0 tuples and 0 log entries</pre></div></div>

<p>Il comando eseguito è autoesplicativo, vengono passati i parametri di connessione (<em>&#8211;connect</em>), l&#8217;identificativo del nodo a cui appartiene il backup (<em>&#8211;nodeid</em>), l&#8217;identificativo del backup (<em>&#8211;backupid</em>), cosa ripristinare (<em>&#8211;restore_meta</em> e <em>-–restore_date</em>) ed infine la directory in cui risiede il backup.<br />
Successivamente, la stessa operazione andrà lanciata dal nodo 3 con le dovute modifiche :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_restore --connect=&quot;nodeid=4;host=management.mycluster.local:1186&quot; --nodeid=3 --backupid=1 --restore_data /mysql/BACKUP/BACKUP-1/
Ndb version in backup files: Version 5.0.12
Connected to ndb!!
_____________________________________________________
Processing data in table: ndb_test/def/test(2) fragment 1
_____________________________________________________
Processing data in table: sys/def/NDB$EVENTS_0(1) fragment 1
_____________________________________________________
Processing data in table: sys/def/SYSTAB_0(0) fragment 1
Restored 0 tuples and 0 log entries</pre></div></div>

<p>Da notare come non sia presente l&#8217;opzione <em>&#8211;restore-meta</em> in quanto essendo i metadati già stati ripristinati nel precedente restore, tale operazione non è più necessaria.<br />
Una volta riavviato dalla macchina di management il server mysqld :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ mysqld --defaults-file=/mysql/my.cnf &amp;</pre></div></div>

<p>Potremo verificare il corretto ripristino della tabella test attraverso la shell del comando mysql :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; use ndb_test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
&nbsp;
Database changed
mysql&gt; show tables;
+--------------------+
| Tables_in_ndb_test |
+--------------------+
| test               |
+--------------------+
1 row in set (0.01 sec)</pre></div></div>

<p><strong>Conclusioni</strong></p>
<p>Ovviamente la tabella di test considerata, non contenendo alcun record, risulta poco attendibile per un test significativo, ma è più che sufficiente per comprendere le meccaniche del funzionamento di questo prodotto. Ciò che si è voluto illustrare è come MySQL Cluster possa rappresentare, una volta debitamente configurato, un&#8217;alternativa gratuita, valida e soprattutto ad alta affidabilità rispetto ad altri costosi concorrenti commerciali.<br />
Segnalo alcuni link da cui ho tratto parte delle informazioni presentate in questi articoli :<br />
Il manuale ufficiale di MySQL Cluster : <a href="http://dev.mysql.com/doc/refman/5.0/en/ndbcluster.html">http://dev.mysql.com/doc/refman/5.0/en/ndbcluster.html</a><br />
Un esempio su come realizzare un cluster a due nodi : <a href="http://www.davz.net/static/howto/mysqlcluster">http://www.davz.net/static/howto/mysqlcluster</a><br />
Dell&#8217;altra ottima documentazione : <a href="http://www.browardphp.com/mysql_manual_en/manual_NDBCluster.html">http://www.browardphp.com/mysql_manual_en/manual_NDBCluster.html</a></p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/">Parte 1</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/">Parte 2</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/">Parte 3</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Dicembre 2005/Gennaio 2006.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL cluster, un database ad alta affidabilità : Parte 2</title>
		<link>http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/</link>
		<comments>http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/#comments</comments>
		<pubDate>Wed, 01 Feb 2006 11:30:19 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Alta affidabilità]]></category>
		<category><![CDATA[MySQL Cluster]]></category>

		<guid isPermaLink="false">http://www.miamammausalinux.org/?p=139</guid>
		<description><![CDATA[In questo secondo articolo cercheremo di capire come si installa e configura il cluster MySQL sulla base dei concetti esposti nel precedente, che ne è l&#8217;ideale introduzione. Preparare l&#8217;ambiente Nel preparare l&#8217;ambiente per il primo test sul cluster MySQL, dobbiamo tenere in considerazione i discorsi affrontati nello scorso articolo sull&#8217;argomento Single Point Of Failure (o [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/mysql.png" alt="mysql" title="mysql" width="100" class="alignnone size-full wp-image-173" /></p>
<p>In questo secondo articolo cercheremo di capire come si installa e configura il cluster MySQL sulla base dei concetti esposti nel precedente, che ne è l&#8217;ideale introduzione.</p>
<p><strong>Preparare l&#8217;ambiente</strong></p>
<p>Nel preparare l&#8217;ambiente per il primo test sul cluster MySQL, dobbiamo tenere in considerazione i discorsi affrontati nello scorso articolo sull&#8217;argomento <em>Single Point Of Failure</em> (o <em>SPOF</em>) e soprattutto, su come questi vadano evitati cercando di ridondare le risorse critiche il cui malfunzionamento potrebbe compromettere la stabilità del sistema.<br />
E&#8217; quindi impensabile, seppur possibile, effettuare dei test su una singola macchina. Il numero minimo di macchine su cui si dovrà lavorare sarà tre. Due nodi di storage ed uno di management.<br />
Sui nodi storage faremo in modo di configurare delle repliche incrociate dei dati per testare, in caso di perdita di un nodo, come il sistema rimanga accessibile. Sul terzo nodo configureremo, oltre al demone per il management al quale i nodi di storage si collegheranno per ricevere le impostazioni di configurazione, anche un demone MySQL server in ascolto per poter manipolare i dati e permettere ad eventuali altre applicazioni di connettersi al cluster.<br />
La struttura del nostro progetto è riassunta in figura1</p>
<div id="attachment_142" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2006/02/mysql-cluster_articolo_2-11-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2006/02/mysql-cluster_articolo_2-11-figura1-300x194.png" alt="Figura 1" title="mysql-cluster_articolo_2-11-figura1" width="300" height="194" class="size-medium wp-image-142" /></a><p class="wp-caption-text">Figura 1</p></div>
<p>Nella figura, fra parentesi viene indicato il nome host. Tale nome verrà indicato nelle configurazioni che effettueremo. Se però non si dispone di un DNS, indicare l&#8217;indirizzo IP sarà comunque corretto.<br />
Un&#8217;utile scappatoia potrebbe essere quella di aggiungere al file <em>/etc/hosts</em> presente in ogni macchina, le righe relative a ciascuna macchina facente parte del nostro cluster, in questa forma :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">127.0.0.1	localhost.localdomain		localhost
192.168.0.1	management.mycluster.local	management
192.168.0.2	storage_a.mycluster.local	storage_a
192.168.0.3	storage_b.mycluster.local	storage_b</pre></div></div>

<p>Certo il progetto non rispetta in pieno le rigide regole anti-SPOF elencate nello scorso articolo, ma trattandosi di un ambiente di test e non di produzione, risulta più che sufficiente.<br />
Nel momento in cui si vorrà portare in produzione il progetto, allora ci si dovrà preoccupare di aumentare il numero di nodi di <em>storage</em> (sempre in numero pari), dividere management e MySQL server e ridondare ciascuno.</p>
<p><strong>Scegliere il corretto software</strong></p>
<p>Abbiamo già spiegato nel precedente articolo come i binari di MySQL che si trovano nelle comuni distribuzioni non abbiano le funzionalità HA. Per ottenere dei binari che soddisfino queste esigenze esistono due metodi : il primo sta nel ricompilare con apposite opzioni i sorgenti, il secondo nell&#8217;utilizzare il pacchetto binario mysql-max.<br />
Salvo esigenze specifiche, utilizzare il pacchetto <em>mysql-max-5.0.12-beta-linux-i686.tar.gz</em> scaricabile da questo indirizzo <a href="http://dev.mysql.com/downloads/mysql/5.0.html">http://dev.mysql.com/downloads/mysql/5.0.html</a> risulta una scelta vincente, mentre per sistemi con architetture differenti come ia64 o amd64, esistono le versioni di mysql-max relative.<br />
Il link indicato porta non a caso alla versione 5.0 del pacchetto, che viene indicata come <em>BETA</em>. Infatti, anche se al momento la versione stabile è la 4.1, nel corso dell&#8217;articolo ci concentreremo sulla 5.0. Per prima cosa perché non manca molto affinché diventi la release ufficiale ad essere distribuita ed inoltre presenta notevoli miglioramenti che vale la pena vedere in funzione.<br />
Un elenco delle funzionalità aggiuntive presenti nella versione 5.0 lo si osserva in figura 2. </p>
<div id="attachment_143" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2006/02/mysql-cluster_articolo_2-11-figura2.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2006/02/mysql-cluster_articolo_2-11-figura2-300x208.png" alt="Figura 2" title="mysql-cluster_articolo_2-11-figura2" width="300" height="208" class="size-medium wp-image-143" /></a><p class="wp-caption-text">Figura 2</p></div>
<p>Sempre all&#8217;indirizzo indicato per i download esiste la possibilità di scaricare anche i pacchetti rpm, convertibili senza problemi per le distribuzioni Debian in pacchetti deb tramite il software alien.<br />
In tutto i pacchetti di binari sono quattro : <em>MySQL-ndb-management</em>, che contiene gli eseguibili per il nodo di management, <em>MySQL-ndb-storage</em>, contenente quelli per i nodi storage ed infine i pacchetti <em>MySQL-ndb-tools</em> e <em>MySQL-ndb-extra</em> contenenti programmi di utilità.<br />
Esiste anche la possibilità di ricompilare manualmente i sorgenti scaricandosi il pacchetto <em>.tar.gz</em> ed indicando in fase di configurazione l&#8217;opzione <em>&#8211;with-ndb-cluster</em>. Tale operazione è però sconsigliata dagli stessi sviluppatori per ragioni di ottimizzazione e stabilità.<br />
Nel corso dell&#8217;articolo utilizzeremo il pacchetto di binari tar.gz su tutte le macchine del cluster, poiché contiene tutti gli eseguibili necessari per far funzionare i nodi di storage, quello di management ed il server MySQL oltre a numerosi programmi di utilità e parecchi esempi.<br />
Nulla vieta, una volta compresi i ruoli dei vari programmi, di utilizzare i pacchetti rpm per le installazioni in modo da ridurre il carico di spazio occupato dall&#8217;installazione.</p>
<p><strong>Installazione</strong></p>
<p>Utilizzando come stabilito i binari precompilati nel pacchetto <em>.tar.gz</em>, l&#8217;installazione è quanto di più semplice possa esservi. Basterà, su ciascuna macchina, scompattare il file in una directory stabilita, ad esempio <em>/usr/local</em>.<br />
Essendo il nome della neo creata directory piuttosto lungo, converrà creare anche un link simbolico che ne faciliti l&#8217;accesso :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ cd /usr/local/
$ tar -xzvf /&lt;directory del file&gt;/mysql-max-5.0.12-beta-linux-i686.tar.gz
$ ln -s  mysql-max-5.0.12-beta-linux-i686 mysql</pre></div></div>

<p>All&#8217;interno di questa directory si trova tutto il necessario per la costruzione del cluster.<br />
Sarà utile creare, sempre su ciascuna macchina, anche una cartella <em>/mysql</em> sotto la quale verranno posti i file di configurazione ed i dati stessi.<br />
Infine, per non dover lanciare i comandi ricorrendo tutte le volte ai path completi, possiamo aggiungere la directory dei binari <em>/usr/local/mysql/bin/</em> alla variabile d&#8217;ambiente <em>$PATH</em>, inserendo questa riga all&#8217;interno del file <em>/etc/profile</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ export PATH=$PATH:/usr/local/mysql/bin/</pre></div></div>

<p>In questo modo tutti gli eseguibili del pacchetto mysql-max saranno disponibili senza che sia necessario indicarne tutto il path.</p>
<p><strong>Configurare il Management server</strong></p>
<p>La configurazione del server di Management risiede in un singolo file, denominato config.ini.<br />
Tale file andrà creato nella directory <em>/mysql</em> del management server con questo contenuto :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">[NDB_MGMD]
id=1
HostName=management
&nbsp;
[NDBD DEFAULT]
NoOfReplicas=2
DataMemory=1950M
IndexMemory=450M
&nbsp;
[NDBD]
id=2
HostName=storage_a
DataDir=/mysql/
&nbsp;
[NDBD]
id=3
HostName=storage_b
DataDir=/mysql/
&nbsp;
[MYSQLD]</pre></div></div>

<p>Come si può notare, il file è diviso in sezioni, ciascuna delle quali inizia con una direttiva tra parentesi quadre. Ogni sezione termina quando inizia l&#8217;altra.<br />
Prima di analizzare nel dettaglio ogni riga inserita, va detto che la configurazione indicata risulta ridotta, nel senso che esistono moltissime direttive per esigenze specifiche e sono tutte documentate da MySQL a questo indirizzo : http://dev.mysql.com/doc/mysql/en/mysql-cluster-config-file.html.</p>
<ul>
<li>[NDB_MGMD] : Contiene le impostazioni relative al management server, nel nostro caso abbiamo dichiarato che tale nodo avrà identificativo 1 e che l&#8217;hostname relativo sarà “management”. Ancora una volta va sottolineato che tale nome deve essere risolto dal DNS, altrimenti il cluster non potrà<br />
funzionare. In alternativa, si può inserire l&#8217;indirizzo IP.</li>
<li>[NDBD_DEFAULT] : Contiene le impostazioni comuni a tutti i nodi dati (NDBD). In questo caso sono stati indicati il numero di repliche (due secondo la struttura illustrata in figura1) e la quantità riservata alla memoria dati e indici.<br />
Tale cifra è ottenibile con questa operazione </p>
<p><em>DataMemory = Node RAM * Total Nodes / Replicas</em></p>
<p>La quantità di memoria degli indici va stabilita in base alle esigenze, un buon compromesso può essere circa il 20% della DataMemory.<br />
I valori indicati nell&#8217;esempio sopra, sono quindi del tutto indicativi, poiché dipendono dalle macchine utilizzate per effettuare i test.</li>
<li>[NDBD] : Ciascuna di queste sezioni contiene le impostazioni del singolo nodo dati, per il quale vengono indicati l&#8217;identificativo numerico, il nome host (o l&#8217;indirizzo IP) e la directory nella quale verranno memorizzati i dati.<br />
Le sezioni NDBD dovranno essere tante quante i nodi dati.</li>
<li>[MYSQLD] : Ciascuna di queste sezioni contiene le impostazioni dei singoli nodi sql. Per nodi sql si intendono server mysql, applicazioni che si basano sulle MySQL cluster API (di cui abbiamo parlato nello scorso articolo) o le stesse applicazioni della suite di mysql-max.<br />
In questo caso è stato previsto quindi un solo client collegabile.</li>
</ul>
<p>La configurazione del nodo di management termina qui, il file config.ini dovrà essere letto dal file eseguibile <em>ndb_mgmd</em>. Questo file eseguibile agirà da demone e rimarrà in ascolto per le connessioni dei nodi dati.</p>
<p><strong>Configurare i nodi storage</strong></p>
<p>Tutte le impostazioni dei nodi dati risiedono sul management server ed ognuno di essi prima di fare qualsiasi cosa vi si connette per capire come è composto il cluster e quale ruolo deve svolgere all&#8217;interno di questo.<br />
Anche in questo caso esiste un file eseguibile che agisce da demone e che consente di effettuare il collegamento, “scaricare” la configurazione dal management server e comunicare con gli altri nodi dati per creare l&#8217;NDB Cluster, questo file è <em>ndbd</em>.<br />
L&#8217;unica cosa da configurare è l&#8217;accesso al server di management, e ciò si ottiene creando un file denominato <em>/etc/my.cnf</em>  che conterrà le impostazioni di configurazione lette da <em>ndbd</em>.<br />
E&#8217; comunque possibile passare all&#8217;eseguibile i dati di connessione direttamente a riga di comando.<br />
Il file <em>/etc/my.cnf</em> conterrà quanto segue :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">[MYSQL_CLUSTER]
ndbcluster
ndb-connectstring=management.mycluster.local</pre></div></div>

<p>Chiaramente quanto scritto andrà ripetuto anche sul secondo nodo dati <em>storage_b</em>.<br />
La configurazione dei nodi storage è così completata.</p>
<p><strong>Configurare il server MySQL</strong></p>
<p>L&#8217;ultima parte della configurazione riguarda il MySQL server che nel nostro caso abbiamo deciso di configurare sulla stessa macchina del management (ma che potrebbe risiedere su di una a se stante).<br />
Per prima cosa, è necessario creare l&#8217;utenza <em>mysql</em> (gruppo <em>mysql</em>) con cui verrà eseguito il server :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ groupadd mysql
$ useradd -g mysql mysql</pre></div></div>

<p>Fatto questo, si può procedere all&#8217;installazione dei database di sistema, utilizzando il file<br />
 contenuto nella cartella <em>scritps/</em> che si trova nell&#8217;alberatura creata dell&#8217;installazione del file <em>tar.gz</em> descritta poco sopra :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ cd /usr/local/mysql/
$ scripts/mysql_install_db -–user=mysql</pre></div></div>

<p>Chiaramente si è forzata l&#8217;utenza mysql per l&#8217;esecuzione delle operazioni per ovvie ragioni di sicurezza.<br />
Una volta completata questa operazione, non rimane che settare i permessi delle directory relative :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ chown -R root:mysql .
$ chown -R mysql data/</pre></div></div>

<p>Come ultima cosa, è necessario creare un file denominato <em>my.cnf</em> ad esempio sotto la cartella <em>/mysql</em> contenente, oltre ad alcune opzioni per il server stesso, le impostazioni di connessione al cluster :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">[MYSQLD]
user=mysql
port=3306
socket=/tmp/mysql.sock
datadir=/usr/local/mysql/data
basedir=/usr/local/mysql
&nbsp;
[MYSQL_CLUSTER]
ndbcluster
ndb-connectstring=management.mycluster.local</pre></div></div>

<p>Le opzioni relative al server MySQL rispecchiano la nostra installazione : l&#8217;utente con cui verrà eseguito il server sarà “mysql”, la porta su cui sarà in ascolto sarà quella standard “3306”, il file di socket per le connessioni sarà /tmp/mysql.sock, le directory dei dati e del server saranno rispettivamente <em>/usr/local/mysql/data</em> e <em>/usr/local/mysql</em>.<br />
Le altre opzioni presenti nell&#8217;area <em>[MYSQL_CLUSTER]</em> sono le stesse dei due nodi storage. Si riferiscono infatti al server di management.<br />
La configurazione del MySQL server è quindi completa.</p>
<p><strong>Avviare il nodo di management</strong></p>
<p>La sequenza in cui le varie componenti del cluster verranno andranno sarà la seguente : server di management, nodi storage ed infine server MySQL.<br />
Come osservato in fase di configurazione, il programma demone che rimarrà in ascolto come management server è <em>ndb_mgmd</em>, questo significa che sulla macchina <em>management.mycluster.local</em> andrà eseguito il seguente comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgmd --config-file=/mysql/config.ini</pre></div></div>

<p>Il parametro passato è ovviamente il file di configurazione da noi creato.<br />
La porta <em>TCP</em> su cui il demone rimane in ascolto è la <em>1186</em>, per verificare quindi che questa sia aperta è possibile lanciare il seguente comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ netstat -natp | grep ndb
tcp        0      0 0.0.0.0:1186            0.0.0.0:*               LISTEN     10303/ndb_mgmd
tcp        0      0 192.168.0.1:35563       192.168.0.1:1186          ESTABLISHED10303/ndb_mgmd
tcp        0      0 192.168.0.1:1186        192.168.0.1:35565         ESTABLISHED10303/ndb_mgmd
tcp        0      0 192.168.0.1:1186        192.168.0.1:35563         ESTABLISHED10303/ndb_mgmd</pre></div></div>

<p>Un output simile quello riportato, indica che il processo è in esecuzione ed in ascolto.<br />
Da questo punto in avanti, per gestire il cluster utilizzeremo il programma <em>ndb_mgm</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm&gt;</pre></div></div>

<p>All&#8217;interno della shell <em>ndb_mgm</em>, è possibile osservare lo stato del cluster, avviare e stoppare i nodi, modificare i metodi di logging e così via. Una panoramica dei comandi disponibili si ottiene digitando help e premendo invio, per il momento, limitiamoci a digitare show e premere invio :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">ndb_mgm&gt; show
Connected to Management Server at: management.mycluster.local:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2 (not connected, accepting connect from storage_a)
id=3 (not connected, accepting connect from storage_b)
&nbsp;
[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.0.1  (Version: 5.0.12)
&nbsp;
[mysqld(API)]   1 node(s)
id=4 (not connected, accepting connect from any host)</pre></div></div>

<p>Si può osservare come sia stata visualizzata tutta la configurazione del cluster : Il management server <em>ndb_mgmd(MGM)</em> è in attesa di connessioni da parte dei due nodi dati <em>ndbd(NDB)</em> (ciascuno dei quali associato alla rispettiva macchina, storage a o b) e di un server MySQL mysqld(API).</p>
<p><strong>Avviare i nodi dati</strong></p>
<p>Per avviare i nodi dati che costituiranno l&#8217;<em>NDB Cluster</em>, dobbiamo recarci su ciascuna delle macchine storage ed avviare il programma ndbd :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndbd</pre></div></div>

<p>Per verificare che il processo sia in esecuzione, possiamo filtrare l&#8217;output del comando ps come segue :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ps aux | grep ndbd
root      3845  0.0  0.0  6476 2872 ?        S    12:41   0:00 ndbd
root      3846  3.5  6.1 1930968 251212 ?    S    12:41   0:00 ndbd
root      3878  0.0  0.0  3692  668 pts/0    S    12:41   0:00 grep ndbd</pre></div></div>

<p>Come si noterà dall&#8217;output, pur avendo lanciato solo una volta il comando, nell&#8217;elenco dei processi si trovano due processi ndbd. Non c&#8217;è nulla di sbagliato in questo, infatti il demone ndbd prevede che esista un processo base che si occupi dei dati ed un processo “angelo custode” che consenta al nodo dati di essere gestito da remoto.<br />
Il concetto si può capire pensando alle operazioni di restart di un nodo che prevedono il kill del processo ndbd ed il suo nuovo avvio. Se dal management server si volesse effettuare un&#8217;operazione come quella descritta ed esistesse un unico processo ndbd sul nodo dati, sarebbe impossibile farlo ripartire una volta stoppato. Vi è quindi la necessità che a guidare le operazioni del processo ndbd principale vi sia un angelo custode.<br />
A questo punto se ritorniamo sul management server e sempre dalla shell ndb_mgm lanciamo il comando show, otterremo quanto segue :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm&gt; show
Connected to Management Server at: management.mycluster.local:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=2    @192.168.0.2  (Version: 5.0.12, Nodegroup: 0, Master)
id=3    @192.168.0.3  (Version: 5.0.12, Nodegroup: 0)
&nbsp;
[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.18.0.1 (Version: 5.0.12)
&nbsp;
[mysqld(API)]   1 node(s)
id=4 (not connected, accepting connect from any host)</pre></div></div>

<p>Quanto visualizzato conferma che i due nodi dati sono correttamente avviati, appartengono ad un unico <em>Nodegroup</em> e che il nodo nodo con id 2 è <em>Master</em>.<br />
Fra tutte le opzioni passabili da riga di comando all&#8217;eseguibile ndbd, due in particolare meritano una spiegazione “-n” e “&#8211;initial”.<br />
“-n” o “&#8211;nostart” sta per “Don&#8217;t start ndbd immediately”, questo significa che il nodo dati diverrà attivo solo quando riceverà il comando start dal management node. Il nodo dati sarà quindi in stato “not started”. Supponiamo di aver avviato a questo punto il nodo dati 3 con il comando “ndbd -n”. Un comando show dalla console di ndb_mgm produrrà quindi tra le altre questa riga :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">[...]
id=3    @192.168.0.3 (Version: 5.0.12, not started)
[...]</pre></div></div>

<p>Il nodo dati 3 rimarrà in stato “not started” sino a che dalla shell di <em>ndb_mgm</em> non verrà forzato lo start del nodo :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">ndb_mgm&gt; 3 start
Database node 3 is being started.</pre></div></div>

<p>Fatto questo, il nodo dati 3 sarà “online” :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">[...]
id=3    @192.168.0.3 (Version: 5.0.12, Nodegroup: 0)
[...]</pre></div></div>

<p>L&#8217;altra importante opzione passabile ad <em>ndbd</em> è “&#8211;initial”. Passare questa opzione significa forzare la pulizia del filesystem relativo al nodo dati. Se l&#8217;initial start è effettuato su di un solo nodo, allora i dati verranno ricostruiti in base alle repliche presenti sull&#8217;altro, mentre se l&#8217;operazione viene effettuata su tutti i nodi, allora l&#8217;intera base dati viene ripulita.<br />
Questa opzione torna utile quando vengono effettuate delle modifiche strutturali al cluster come ad esempio la modifica della memoria disponibile.<br />
Vedremo nel prossimo articolo come sfruttare questo parametro.</p>
<p><strong>Avviare il mysqld</strong></p>
<p>Per avviare il mysqld basterà lanciare il comando mysqld a cui andrà passato il percorso del file di configurazione creato poco sopra tramite l&#8217;opzione “&#8211;defaults-file=” :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ mysqld --defaults-file=/mysql/my.cnf &amp;</pre></div></div>

<p>Il carattere &#038; alla fine del comando consente di mettere il processo in background per poter continuare a lavorare nella console.<br />
E&#8217; possibile inoltre verificare che il processo mysqld sia in ascolto sulla porta configurata :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ netstat -natp | grep mysqld
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      15129/mysqld
tcp        0      0 192.168.0.1:34398          192.168.0.1:1186           ESTABLISHED 15129/mysqld
tcp        0      0 192.168.0.1:34402          192.168.0.2:32782          ESTABLISHED 15129/mysqld
tcp        0      0 192.168.0.1:34401          192.168.0.3:32779          ESTABLISHED 15129/mysqld</pre></div></div>

<p>A questo punto l&#8217;avvio del cluster può dirsi completato, infatti <em>ndb_mgm</em> conferma che tutte le componenti sono operative :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm&gt; show
Connected to Management Server at: management.mycluster.local:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
&nbsp;
&nbsp;
&nbsp;
&nbsp;
id=2    @192.168.0.2  (Version: 5.0.12, Nodegroup: 0)
id=3    @192.168.0.3  (Version: 5.0.12, Nodegroup: 0, Master)
&nbsp;
[ndb_mgmd(MGM)] 1 node(s)
id=1    @192.168.0.1  (Version: 5.0.12)
&nbsp;
[mysqld(API)]   1 node(s)
id=4    @192.168.0.1  (Version: 5.0.12)</pre></div></div>

<p><strong>Utilizzo del motore NDB</strong></p>
<p>Per effettuare dei test di funzionamento del motore cluster, utilizzeremo il programma client MySQL  dalla macchina di management :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">$ /usr/local/mysql/bin/mysql
&nbsp;
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 2 to server version: 5.0.12-beta-max
&nbsp;
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
&nbsp;
mysql&gt;</pre></div></div>

<p>Per prima cosa verificheremo che nell&#8217;elenco dei motori MySQL disponibili sia presente anche quello del cluster <em>NDB</em>, con questo comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; show engines;
+------------+---------+----------------------------------------------------------------+
| Engine     | Support | Comment                                                        |
+------------+---------+----------------------------------------------------------------+
...
|
| NDBCLUSTER | YES     | Clustered, fault-tolerant, memory-based tables                 |
| NDB        | YES     | Alias for NDBCLUSTER                                           |
...
+------------+---------+----------------------------------------------------------------+
18 rows in set (0.00 sec)</pre></div></div>

<p>Se tra le righe risultanti appariranno anche quelle relative ad <em>NDBCLUSTER</em>, avremo la conferma del supporto al motore cluster da parte del server MySQL installato sulla macchina di management.<br />
Occorre però un chiarimento. Tale server possiede le medesime funzionalità di un comune server MySQL ed anzi, se non si sfruttano direttive particolari in fase di creazione delle tabelle, queste verranno gestite dal motore di default, che si chiama MyISAM, e non dal motore NDB.<br />
Per capire meglio questo concetto, procediamo col creare un database di test :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; CREATE DATABASE ndb_test;
Query OK, 1 row affected (0.00 sec)</pre></div></div>

<p>All&#8217;interno creeremo una semplice tabella da un campo di tipo integer contenente un singolo valore :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; USE ndb_test;
Database changed
mysql&gt; CREATE TABLE test (i INT);
Query OK, 0 rows affected (0.02 sec)
&nbsp;
mysql&gt; INSERT INTO test (i) VALUES (1);
Query OK, 1 row affected (0.00 sec)
&nbsp;
mysql&gt; SELECT * FROM test;
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)</pre></div></div>

<p>Al momento la tabella NON è ancora gestita dal motore <em>NDB</em>, e ciò è confermato da questo comando :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; SHOW CREATE TABLE test;
+-------+-----------------------------------------------------------------------------------------+
| Table | Create Table                                                                            |
+-------+-----------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `i` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+-------+-----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)</pre></div></div>

<p><em>ENGINE=MyISAM</em> indica infatti che la tabella viene gestita localmente dal motore <em>MyISAM</em>.<br />
Per fare in modo di porre sotto motore <em>NDB</em> la tabella, è necessario forzare il motore da usare in fase di creazione, aggiungendo alla fine del comando <em>CREATE TABLE</em> la clausola <em>ENGINE=NDBCLUSTER</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; CREATE TABLE test (i INT) ENGINE=NDBCLUSTER;</pre></div></div>

<p>oppure modificare la tabella appena creata come segue :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; ALTER TABLE test ENGINE=NDBCLUSTER;
Query OK, 1 row affected (0.44 sec)
Records: 1  Duplicates: 0  Warnings: 0</pre></div></div>

<p>A questo punto i dati della tabella (una sola, importantissima riga !) sono replicati sui nodi del cluster e sono raggiungibili attraverso il server <em>mysqld</em> da qualsiasi applicazione :</p>

<div class="wp_syntax"><div class="code"><pre class="console" style="font-family:monospace;">mysql&gt; SHOW CREATE TABLE test;
+-------+---------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                |
+-------+---------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `i` int(11) default NULL
) ENGINE=ndbcluster DEFAULT CHARSET=latin1 |
+-------+---------------------------------------------------------------------------------------------+
1 row in set (0.05 sec)</pre></div></div>

<p>Un ultimo importante chiarimento riguarda eventuali altri server MySQL che potranno essere collegati al <em>cluster NDB</em>. Infatti il motore <em>NDB</em> agisce a livello di tabelle non di database. Questo significa che non è il database ad essere replicato, ma solo le tabelle. Su ciascun ulteriore server MySQL collegato dovranno quindi esistere i database relativi. Nel nostro caso ad esempio, se volessimo accedere alla tabella test da un&#8217;altro server MySQL configurato nel management server, dovremmo prima creare il database <em>ndb_test</em> al cui interno, senza fare nient&#8217;altro, troveremo le tabelle del cluster.</p>
<p><strong>Conclusioni</strong></p>
<p>Abbiamo visto in questo articolo come configurare ed avviare il cluster MySQL creando al suo interno una tabella di test.<br />
Nel prossimo impareremo a consultare i log, effettueremo dei test di funzionamento simulando dei crash sui singoli nodi per accertarci che non esistano SPOF ed effettueremo modifiche sulla struttura del database. Infine impareremo ad effettuare backup e restore dei dati in modo da poter approfondire tutte le funzionalità di questo interessante progetto.</p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/">Parte 1</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/">Parte 2</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/">Parte 3</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Dicembre 2005/Gennaio 2006.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL cluster, un database ad alta affidabilità : Parte 1</title>
		<link>http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/</link>
		<comments>http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/#comments</comments>
		<pubDate>Thu, 01 Dec 2005 11:30:22 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Alta affidabilità]]></category>
		<category><![CDATA[MySQL Cluster]]></category>

		<guid isPermaLink="false">http://www.miamammausalinux.org/?p=127</guid>
		<description><![CDATA[Cerchiamo di capire con questa serie di articoli come sia possibile impiegare il più famoso database utilizzato per applicazioni web in soluzioni di alta affidabilità. MySQL : Solo un server SQL ? Quanti non hanno sentito parlare almeno una volta di MySQL ? MySQL è il database più diffuso sul web per una svariata serie [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/mysql.png" alt="mysql" title="mysql" width="100" class="alignnone size-full wp-image-173" /></p>
<p>Cerchiamo di capire con questa serie di articoli come sia possibile impiegare il più famoso database utilizzato per applicazioni web in soluzioni di alta affidabilità.</p>
<p><strong>MySQL : Solo un server SQL ?</strong></p>
<p>Quanti non hanno sentito parlare almeno una volta di MySQL ? MySQL è il database più diffuso sul web per una svariata serie motivi, la velocità, la facilità d&#8217;impiego, la semplicità di accesso ed il supporto per i sistemi operativi più utilizzati. E&#8217; inoltre un progetto Opensource che pur avendo alla base una reale azienda che deve produrre profitto, la svedese MySQL AB, distribuisce il proprio software liberamente.<br />
Il database infatti è liberamente scaricabile dal sito ufficiale <a href="http://www.mysql.com">http://www.mysql.com</a> nelle versioni per i sistemi operativi Linux, Solaris, Mac OSX, FreeBSD e tantissimi altri. Un elenco completo delle piattaforme supportate si trova a questo indirizzo : <a href="http://dev.mysql.com/downloads/mysql/5.0.html">http://dev.mysql.com/downloads/mysql/5.0.html</a>.<br />
Detto questo, quello che molti non sanno è che MySQL AB sta sviluppando in parallelo al motore database standard anche una versione cluster, quello che viene definito un database ad alta affidabilità. Il progetto originale partì dalla necessità di un&#8217;importante azienda di telefonia di avere un motore database ad alta affidabilità che permettesse ricerche estremamente rapide.<br />
La struttura relativamente semplice degli archivi dell&#8217;azienda si coniugava alla perfezione con le funzionalità offerte da MySQL, a cui mancava soltanto il supporto per l&#8217;alta affidabilità. Il prodotto finale di questi studi fu appunto MySQL cluster che da allora MySQL AB continua a far crescere in parallelo al motore standard.<br />
Cercheremo di capire nel corso di questo articolo (e dei successivi) come funzioni e quali siano le potenzialità di questo progetto.</p>
<p><strong>Cos&#8217;è un database ad alta affidabilità ?</strong></p>
<p>Un database ad alta affidabilità (o <em>HA</em>, <em>High Available</em>) è semplicemente quello che dice di essere : una base dati sempre disponibile, che presenta ridondanza di processi e di dati, che non ha cioè singoli punti di rottura (o <em>SPOF</em>, <em>Single Point Of Failure</em>).<br />
All&#8217;interno di un&#8217;architettura senza SPOF tutte le componenti presenti (Hardware e Software) sono ridondate. Se una componente smette di funzionare, l&#8217;integrità del sistema non è compromessa.<br />
Tale concetto viene applicato a tutti i tipici cluster di servizi, come nel caso di uno share di rete <em>NFS</em> o un Web server debbano essere ridondati al fine di garantire che, in caso di interruzione dei processi principali, i servizi continuino ad essere erogati.<br />
In un database, avere ridondanza di processi significa che se per una qualsiasi ragione, il processo Master (ossia quello a cui le applicazioni client fanno solitamente riferimento) dovesse cadere, il database rimarrebbe comunque accessibile (grazie ad un secondo processo, che diventerebbe a sua volta Master).<br />
Avere ridondanza di dati invece, significa che il dato non è registrato in una singola posizione. Se questo si corrompe quindi, si ha la possibilità di ripristinarne il contenuto in base alla sua copia che risiede in una diversa posizione.<br />
Tutte queste funzionalità permettono di avere un database senza SPOF : se si dovesse danneggiare una qualsiasi componente, logica o fisica, il sistema non risulterebbe compromesso.</p>
<p><strong>Come ottenere un database ad alta affidabilità ?</strong></p>
<p>Definito quindi il concetto di database HA, va capito nella realtà come sia possibile ottenerne uno, ovvero come si possano eliminare tutti i potenziali <em>SPOF</em>.<br />
Il discorso <em>SPOF</em> non va sottovalutato, ma è necessario porsi dei limiti nella considerazione di tutti i possibili punti di rottura. Questo significa che se una singola macchina risulta essere un unico <em>SPOF</em>, ed è quindi necessario averne due, allora anche la stanza in cui saranno presenti le due macchine sarà uno <em>SPOF</em> e quindi sarebbe bene separare in stanze diverse le due macchine, ma a quel punto l&#8217;edificio stesso diventerebbe uno <em>SPOF</em> e proseguendo di questo passo si arriverebbe ben presto a capire come l&#8217;universo stesso sia un unico immenso <em>SPOF</em> !<br />
Quindi, senza tirare in ballo la meccanica quantistica per creare un database cluster, è chiaro come sia necessario trovare il giusto equilibrio tra affidabilità e funzionalità.<br />
Separare su macchine diverse le componenti del database è un buon compromesso : i processi, ossia la parte software che permette l&#8217;accesso al dato ed i dati stessi saranno su macchine distinte.<br />
Questa logica, divide il cluster in due livelli : quello SQL, inerente ai processi, e quello Storage, inerente ai dati. Entrambi i livelli devono essere esenti da <em>SPOF</em> e devono quindi prevedere ridondanza.</p>
<p><strong>La ridondanza di processi (livello SQL)</strong></p>
<p>E&#8217; necessario che il motore Sql che gestisce le richieste di accesso e le operazioni di lettura/scrittura sia sempre disponibile. Ad un motore Sql generalmente corrisponde un processo in ascolto presso un determinato indirizzo IP su una particolare porta. Rendere questa situazione ridondata, significa avere più di un motore Sql. Ciascuno di questi motori, idealmente, dovrebbe essere posto dietro ad un bilanciatore, cioè un software che renda disponibile un solo indirizzo IP di riferimento ma che distribuisca il carico delle richieste effettuate attraverso tutti i motori che sono stati configurati. Esistono diversi software adatti a questo scopo, ma una discussione in merito andrebbe oltre gli scopi del presente articolo. Per il momento, si può concludere dicendo che questa situazione eliminerebbe il <em>SPOF</em> legato al motore Sql.</p>
<p><strong>La ridondanza dei dati (livello Storage)</strong></p>
<p>Al pari della ridondanza dei processi, che riguarda più che altro l&#8217;alta affidabilità dell&#8217;accesso alla base dati, c&#8217;è la ridondanza dei dati stessi, che si può ottenere sostanzialmente in due modi o con  una combinazione di entrambi : la ridondanza fisica e la ridondanza logica.<br />
Per ottenere ridondanza fisica è sufficiente avere hardware dedicato a questo scopo, ad esempio  controller <em>RAID</em> che gestiscano la duplicazione dei dati su due o più dischi in maniera trasparente. In caso di rottura fisica del disco, questa viene segnalata in modo da poter essere corretta (con la sostituzione del disco), ma l&#8217;accesso ai dati rimane comunque garantito.<br />
Un po&#8217; più complicato è il discorso relativo alla ridondanza logica. Per capire questo concetto, è necessario comprendere il significato di replica. Il numero di repliche all&#8217;interno di un database   indica il numero copie multiple dello stesso dato. Le operazioni effettuate sul dato sono replicate su tutte le copie e fino a che questa operazione non è completata, la transazione che ha generato la modifica non è considerata conclusa. E&#8217; chiaro quindi come esistano repliche primarie (le prime ad essere utilizzate) e repliche secondarie (le copie effettive) ed è altrettanto logico che avere due repliche del medesimo dato sullo stesso sistema non rispetti il principio dell&#8217;assenza di <em>SPOF</em>.<br />
La soluzione ideale quindi sarebbe quella di avere come minimo due repliche distribuite su due diversi sistemi, come in figura 1.</p>
<div id="attachment_128" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura1-300x245.png" alt="Figura 1" title="mysql-cluster_articolo_1-11-figura1" width="300" height="245" class="size-medium wp-image-128" /></a><p class="wp-caption-text">Figura 1</p></div>
<p>Qui l&#8217;intero database è diviso in due partizioni. Nel primo sistema abbiamo la replica primaria della prima partizione e la replica secondaria della seconda partizione, mentre nel secondo, viceversa, è presente la replica primaria della seconda partizione e quella secondaria della prima. In questo modo in caso di rottura, blocco o qualsiasi evento comprometta il funzionamento di uno dei due sistemi, l&#8217;intera base dati è ricostruibile e l&#8217;accesso ai dati sempre disponibile.</p>
<p>La situazione ideale quindi, prevede che esista una base dati distribuita su almeno due sistemi, ciascuno dei quali contenente la propria replica primaria e la secondaria dell&#8217;altro sistema.  L&#8217;accesso ai dati sarà reso disponibile da due motori Sql attraverso un unico indirizzo <em>IP</em>, gestito dal bilanciatore che distribuirà il carico delle richieste. In tutta questa struttura esiste un solo <em>SPOF</em> che è rappresentato dal bilanciatore stesso, che quindi a sua volta andrebbe ridondato.<br />
Questa è la situazione perfetta (forse paranoica !) ed è illustrata in figura 2.</p>
<div id="attachment_129" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura2.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura2-300x248.png" alt="Figura 2" title="mysql-cluster_articolo_1-11-figura2" width="300" height="248" class="size-medium wp-image-129" /></a><p class="wp-caption-text">Figura 2</p></div>
<p><strong>MySQL cluster</strong></p>
<p>Definita quindi la struttura generale dei database cluster, possiamo spostare la nostra attenzione su come è composto un cluster MySQL.<br />
Come tutti i database cluster, anche quello MySQL presenta la consueta architettura a due livelli : il livello SQL ed il livello Storage, denominato anche NDB Cluster, dove l&#8217;acronimo NDB sta per Network DataBase.<br />
Ciascuna componente presente in un livello, è definita Nodo. Esisteranno quindi nodi client, ossia componenti appartenenti al livello SQL e nodi dati, cioè componenti del livello storage. Esiste anche una terza tipologia di nodo, denominato di management (gestione) che rappresenta il fulcro intorno al quale ruota il MySQL cluster e sul quale verrà fatto un discorso a parte.</p>
<p><strong>I nodi client</strong></p>
<p>I nodi client sono ciò che permettono alle utenze di effettuare operazioni sui dati e si dividono essenzialmente in tre categorie :</p>
<ol>
<li>Istanze dei server MySQL : la maggioranza dei casi, veri e propri server MySQL che si connettono alla base dati e si interfacciano all&#8217;esterno attraverso i classici processi demone mysqld.</li>
<li>Applicazioni esterne che utilizzano l&#8217;accesso nativo ai dati : si tratta di applicazioni che non usano l&#8217;intermediario MySQL per accedere al database, ma lo fanno direttamente utilizzando quelle che vengono definite NDB API. Questi client effettuano l&#8217;accesso ai dati direttamente dal codice del programma costruito.</li>
<li>Client nativi del cluster MySQL : ossia le applicazioni stesse del cluster, programmi cioè che consentono l&#8217;accesso e la manutenzione del cluster attraverso ad esempio operazioni di backup o restore. Tali applicazioni sono denominate NDB clients.</li>
</ol>
<p>Tutti e tre i casi illustrati consentono all&#8217;utente di avere un interfaccia di accesso ai dati, in alcuni casi “consueta” (Il tipico server MySQL) ed in altri meno (le NDB API, delle quali bisogna avere una conoscenza piuttosto approfondita della programmazione database a basso livello).</p>
<p><strong>I nodi dati</strong></p>
<p>I nodi dati sono la struttura che si occupa della memorizzazione effettiva dei dati e compongono il già citato NDB Cluster.<br />
Tutta quest&#8217;area lavora in maniera trasparente rispetto ai client. Il modo e la posizione in cui i dati vengono frammentati e la gestione delle repliche non sono conosciute dai client. Essi accedono, con i metodi illustrati poco sopra, solo all&#8221;entità NDB cluster.<br />
A ciascuno dei nodi dati è associato un processo demone denominato ndbd.<br />
Una cosa importante da capire è la sostanziale differenza di NDB cluster dagli altri prodotti database cluster in commercio, come ad esempio Oracle RAC. In questi infatti, l&#8217;alta affidabilità è garantita da una totale ridondanza. Questo significa che esistono due macchine identiche, ma una sola è attiva e si preoccupa di tenere allineata la seconda che rimane pronta a subentrare in caso di guasto.<br />
All&#8217;interno di NDB cluster, tutti i nodi che fanno parte del sistema pur rispettando le regole di ridondanza e assenza di SPOF, contribuiscono al funzionamento del cluster incrementandone notevolmente le prestazioni.</p>
<p><strong>Il nodo management</strong></p>
<p>La parte più importante del cluster MySQL è rappresentata dal nodo di management, il nodo al quale tutte le componenti del cluster si connettono appena avviate per conoscere il resto del sistema.<br />
In questo nodo è configurata la struttura del cluster : quanti e quali sono i nodi dati, quante repliche avranno le partizioni del sistema, quanta memoria sarà disponibile e così via.<br />
Dal nodo di management è possibile avviare e stoppare i nodi dati, verificare lo stato del loro funzionamento, effettuare backup e restore, settare la tipologia dei log di ciascun client e stoppare l&#8217;intero cluster.<br />
E&#8217; interessante notare che, una volta che il cluster sia stato avviato, il nodo di management potrebbe tranquillamente smettere di funzionare. Tutti i nodi del cluster infatti, una volta ricevuti i parametri di configurazione dal nodo di management, iniziano a comunicare direttamente fra loro. Certo è che se si dovesse interrompere il processo del nodo di management sarebbe impossibile effettuare le altre operazioni descritte sopra, ma è importante capire che il cluster stesso, una volta che sia completamente avviato, sia indipendente dal nodo di management.<br />
Il nodo di management è un processo demone, avviato tramite un file eseguibile chiamato ndb_mgmd che rimane in ascolto su una porta alle richieste dei nodi client.</p>
<p>In figura 3 viene illustrata la struttura logica del cluster MySQL.</p>
<div id="attachment_130" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura3.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura3-300x245.png" alt="Figura 3" title="mysql-cluster_articolo_1-11-figura3" width="300" height="245" class="size-medium wp-image-130" /></a><p class="wp-caption-text">Figura 3</p></div>
<p><strong>Replicazione e frammentazione dei dati nel cluster MySQL</strong></p>
<p>Ora che abbiamo capito la logica del cluster MySQL cerchiamo di concentrarci su come esso tratti la distribuzione dei dati. Questa è divisa in due parti : la frammentazione dei dati e la replicazione degli stessi.<br />
La frammentazione dei dati consiste nel partizionare una tabella in un numero pari di frammenti che vengono divisi all&#8217;interno di un numero pari di nodi. La replicazione consiste nella duplicazione dei frammenti all&#8217;interno dei nodi.<br />
Osserviamo la figura 4 :</p>
<div id="attachment_131" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura4.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura4-300x178.png" alt="Figura 4" title="mysql-cluster_articolo_1-11-figura4" width="300" height="178" class="size-medium wp-image-131" /></a><p class="wp-caption-text">Figura 4</p></div>
<p>In questo esempio, il database è organizzato in due nodi e due repliche. Tutto si rifà alla teoria dei cluster di database che abbiamo precedentemente spiegato ed illustrato in figura1. Qui ciò che veniva chiamato partizione è chiamato frammento ma il concetto non cambia : ciascun frammento di tabella è presente su entrambi i nodi, in un nodo come frammento primario e nell&#8217;altro come replica di questo. Il danneggiamento di un nodo non compromette l&#8217;intero sistema in quanto ogni sistema possiede le informazioni necessarie a ricostruire il totale delle informazioni presente nel sistema.<br />
Si noterà come nella figura venga menzionato il “Nodegroup”.<br />
All&#8217;interno del cluster MySQL il numero di Nodegroup si ottiene con questa semplice equazione :</p>
<p><em>Numero di Nodegroup = Numero di data nodes / Numero di repliche</em></p>
<p>Nel caso di figura4 quindi con due nodi dati e due repliche avremo un solo Nodegroup. Se invece avessimo a disposizione quattro macchine, potremmo organizzare il carico come illustrato in figura5, dove esistono 4 nodi dati con due repliche e quindi due NodeGroups.<br />
Le tabelle in questo esempio sono frammentate in quattro partizioni e sono divise a coppie nei Nodegroup : ciascun Nodegroup contiene metà delle informazioni del database e ciascun nodo dati possiede un frammento primario dei quattro in cui è divisa la tabella.<br />
Anche questa struttura non possiede SPOF.</p>
<div id="attachment_132" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura5.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura5-300x128.png" alt="Figura 5" title="mysql-cluster_articolo_1-11-figura5" width="300" height="128" class="size-medium wp-image-132" /></a><p class="wp-caption-text">Figura 5</p></div>
<p>Le combinazioni possibili del numero di repliche, dati e nodi non devono superare i limiti del cluster MySQL che sono di un massimo di : 4 repliche dei dati, 48 nodi dati, 64 nodi totali. Lavorando per coerenza con un numero pari di repliche e nodi dati, si possono ottenere situazioni che partono da due nodi con due repliche fino a quarantotto nodi con quattro repliche.<br />
E&#8217; chiaro che maggiore sarà il numero di repliche, minori saranno le performance in quanto le transazioni di scrittura non saranno completate sino a che l&#8217;informazione non verrà scritta in tutte le sue repliche.</p>
<p><strong>Come organizzare CPU e Memoria sui nodi dati</strong></p>
<p>L&#8217;organizzazione delle risorse fisiche del database è abbastanza semplice, nel senso che esistono delle regole precise su cui basarsi. </p>
<p><em>CPU</em></p>
<p>Ogni nodo dati deve essere associato ad una CPU, quindi è perciò sconsigliato configurare un sistema a singola CPU affinché esegua più di un processo ndbd (ossia il processo nodo dati del cluster). Per eseguire più di un nodo dati su una singola macchina è necessario usare sistemi Multi CPU, ma bisogna ricordarsi di eliminare lo SPOF macchina singola, pertanto, è necessario predisporre un minimo di due macchine con dual CPU.<br />
Anche dal punto di vista logico, nel momento in cui si decide di mettere sulla stessa macchina due nodi data, è bene separare le risorse in modo che se una macchina va in crash il sistema non risulta compromesso : quindi nel caso in cui si decida di avere un database con quattro nodi data distribuiti su due macchine dual CPU sarà bene organizzare i Nodegroup come in figura 6 :</p>
<div id="attachment_133" class="wp-caption alignnone" style="width: 310px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura6.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2005/12/mysql-cluster_articolo_1-11-figura6-300x126.png" alt="Figura 6" title="mysql-cluster_articolo_1-11-figura6" width="300" height="126" class="size-medium wp-image-133" /></a><p class="wp-caption-text">Figura 6</p></div>
<p>Con questa organizzazione, se anche una macchina va in crash, il sistema non è compromesso.</p>
<p><em>Memoria</em></p>
<p>La quantità di memoria disponibile nel cluster, viene calcolata con questa semplice equazione :</p>
<p><em>Memoria totale cluster = Memoria RAM Nodo dati * Numero totale di nodi / Numero di repliche</em></p>
<p>Quindi se avremo quattro gigabyte di memoria su ogni nodo dati, quattro nodi dati totali e due repliche, il nostro cluster avrà otto gibabyte di memoria disponibile.</p>
<p><strong>Conclusioni</strong></p>
<p>Abbiamo visto in questo articolo come è strutturato logicamente e come funziona il cluster MySQL. Nel prossimo eseguiremo una prova effettiva, configurando un cluster a due nodi ed imparando a gestire il tutto dal Management server.</p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/">Parte 1</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/02/mysql-cluster-un-database-ad-alta-affidabilita-parte-2/">Parte 2</a><br />
MySQL cluster, un database ad alta affidabilità : <a href="http://www.miamammausalinux.org/2006/03/mysql-cluster-un-database-ad-alta-affidabilita-parte-3/">Parte 3</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Dicembre 2005/Gennaio 2006.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2005/12/mysql-cluster-un-database-ad-alta-affidabilita-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Una classe PHP per l&#8217;accesso a Firebird &#8211; Parte 3: Gestione delle Transazioni</title>
		<link>http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/</link>
		<comments>http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/#comments</comments>
		<pubDate>Wed, 01 Dec 2004 11:30:45 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Firebird]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programmazione]]></category>
		<category><![CDATA[Applicazioni Web]]></category>
		<category><![CDATA[Sviluppo]]></category>

		<guid isPermaLink="false">http://localhost/miamammausalinux.org/?p=78</guid>
		<description><![CDATA[&#160;&#160;&#160;&#160; Negli articoli precedenti abbiamo costruito parte di una classe PHP per l&#8217;accesso ad un database Firebird. Allo stato attuale delle cose, la nostra classe ci consente di effettuare query, navigare nei resultset ed operare sui campi BLOB. In questo articolo cercheremo di completare il lavoro provando a capire cosa sono le Transazioni ed implementando [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/firebird.png" alt="firebird" title="firebird" width="100" class="alignnone size-full wp-image-171" />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/php.png" alt="php" title="php" width="100" class="alignnone size-full wp-image-175" /></p>
<p>Negli articoli precedenti abbiamo costruito parte di una classe PHP per l&#8217;accesso ad un database Firebird. Allo stato attuale delle cose, la nostra classe ci consente di effettuare query, navigare nei resultset ed operare sui campi BLOB.<br />
In questo articolo cercheremo di completare il lavoro provando a capire cosa sono le Transazioni ed implementando un metodo che ci consenta di gestirle al meglio.</p>
<p><strong>Panoramica sulle Transazioni</strong></p>
<p>Nell&#8217;operare su basi dati complesse può capitare che per effettuare una determinata operazione sia necessario più di un singolo passo, ad esempio : Un cliente si collega ad un servizio B2B ed inserisce il suo ordine.<br />
Quella che appare come una banale operazione di inserimento in realtà a livello dati potrebbe comportare ad esempio la scrittura della testata d&#8217;ordine nella tabella ordini, dei dettagli ordine in un&#8217;altra tabella contenente le varie righe, l&#8217;aggiornamento della tabella dello storico ordini ed infine l&#8217;aggiornamento del campo “data ultima operazione” nella tabella dei clienti.<br />
Come si può facilmente capire, la singola operazione “inserisci ordine” è in realtà composta da 4 sotto-operazioni che dipendono l&#8217;una dall&#8217;altra in maniera inscindibile : se venissero inserite le righe di dettaglio dell&#8217;ordine senza che l&#8217;operazione di registrazione della testata fosse andata a buon fine, il database si troverebbe in uno stato inconsistente e non permetterebbe di effettuare l&#8217;inserimento restituendo un messaggio di errore.<br />
Per mantenere la coerenza della nostra base dati, nel momento in cui una qualsiasi delle nostre sotto-operazioni dovesse fallire, anche tutte le altre andrebbero annullate.<br />
In questo caso ed in mille altri simili, fare a meno delle Transazioni è praticamente impossibile.<br />
Per definizione quindi, una Transazione è un&#8217;insieme di istruzioni SQL che deve essere trattato come un&#8217;unita&#8217; “atomica”, cioe&#8217; non scomponibile. Una Transazione viene completata solo se tutte le operazioni che la compongono vengono eseguite con successo. Nel caso in cui una delle operazioni fallisce oppure la Transazione viene esplicitamente annullata, tutte le operazioni precedenti devono essere ritenute nulle, come se non fossero mai state effettuate.<br />
Usare le Transazioni risulta inoltre particolarmente utile nell&#8217;implementazione di meccanismi di locking (blocco) per permettere un accesso concorrente ai dati di un database, in quanto le modifiche operate sul database dalle istruzioni di una Transazione non hanno effetto su questo (e quindi non sono visibili ad altre Transazioni) fino a quando la Transazione non viene completata con successo.<br />
Ogni volta che una Transazione viene avviata può concludersi in due modi : Successo o Insuccesso.<br />
In caso di successo tutti gli inserimenti, cancellazioni e aggiornamenti vengono registrati nel database, in caso di insuccesso, il database non sarà in alcun modo modificato e si troverà nello stato immediatamente precedente all&#8217;avvio della Transazione.</p>
<p><strong>Avviare una Transazione in Firebird</strong></p>
<p>In Firebird ogni operazione effettuata su un database in realtà è parte di una Transazione. Nel momento stesso in cui viene effettuata una connessione ad un database, viene avviata, in maniera automatica e trasparente ai nostri occhi, una Transazione “di default”, che parte cioè automaticamente, senza bisogno di avviarla tramite istruzioni SQL.<br />
Questo concetto viene spiegato con un esempio nel riquadro 1, e va chiarito da subito che non limita in alcun modo la possibilità di definire proprie Transazioni.<br />
Per avviare manualmente una Transazione, è necessario utilizzare questa istruzione SQL :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SET</span> TRANSACTION <span style="color: #66cc66;">&lt;</span>ACCESS MODE<span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">&lt;</span>LOCK RESOLUTION<span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">&lt;</span>ISOLATION LEVEL<span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">&lt;</span>TABLE RESERVATION<span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">&lt;</span>DATABASE SPECIFICATION<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Cerchiamo di capire in maniera sintetica il significato di ciascuno dei parametri passabili all&#8217;istruzione :</p>
<p><em>ACCESS MODE</em> : può essere READ ONLY o READ WRITE, questo parametro descrive il tipo di accesso effettuabile dalla Transazione sulle tabelle del database, se di sola lettura o di lettura e scrittura.</p>
<ul>
<li><em>LOCK RESOLUTION</em> : può essere WAIT o NO WAIT e descrive il tipo di comportamento che la Transazione deve assumere di fronte a record posti in stato di blocco (LOCK). Nel primo caso la Transazione attenderà sino a che il record non sarà sbloccato, nel secondo caso genererà un errore di tipo “LOCK CONFLICT”.</li>
<li><em>ISOLATION LEVEL</em> : può essere SNAPSHOT, SNAPSHOT TABLE STABILITY o READ COMMITTED. Questo parametro descrive l&#8217;iterazione della Transazione con le altre (eventuali) in corso, il tipo di accesso alle medesime tabelle. Se dichiariamo SNAPSHOT, verrà restituita ad un&#8217;altra Transazione la vista del database al momento in cui la nostra è inziata; Indicando SNAPSHOT TABLE STABILITY non verranno consentite modifiche da parte di altre Transazioni alle tabelle che la nostra sta leggendo o updatando; per finire, con READ COMMITTED verrà consentito l&#8217;update sull&#8217;ultima versione registrata (quindi conclusa con una COMMIT RETAIN, la cui spiegazione viene affrontata nel paragrafo “Terminare una Transazione”) della riga in questione.</li>
<li><em>TABLE RESERVATION</em> : consente indicando RESERVING di bloccare immediatamente l&#8217;accesso alle tabelle che verranno indicate.</li>
<li><em>DATABASE SPECIFICATION</em> : indicando USING si può specificare una serie di database disponibili ai quali questa Transazione può accedere.</li>
</ul>
<p>Utilizzare la Transazione di default equivale a dichiarare quanto segue :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SET</span> TRANSACTION <span style="color: #993333; font-weight: bold;">READ</span> <span style="color: #993333; font-weight: bold;">WRITE</span> WAIT ISOLATION LEVEL SNAPSHOT;</pre></div></div>

<p>Quindi per necessità diverse, saranno diversi i parametri che verranno passati all&#8217;istruzione SQL.<br />
E&#8217; possibile anche nominare le Transazioni, per distinguerle l&#8217;una dall&#8217;altra. L&#8217;argomento in se richiederebbe un&#8217;articolo a parte e non riguarda direttamente lo scopo del nostro articolo, quindi<br />
ricordo che per approfondire l&#8217;argomento un&#8217;ottimo strumento gratuito rimane la documentazione di Interbase 6 scaricabile dal sito ufficiale di Firebird :<br />
<a href="http://firebird.sourceforge.net/index.php?op=doc&#038;id=userdoc">http://firebird.sourceforge.net/index.php?op=doc&#038;id=userdoc</a><br />
in particolare il capitolo 4 del libro “EMBEDDED SQL GUIDE” : “WORKING WITH TRANSACTIONS”.</p>
<p><strong>Terminare una Transazione</strong></p>
<p>Ora che è chiaro come viene avviata una Transazione, prima di proseguire, cerchiamo di capire come è possibile terminarla. Come già accennato i due stadi possibili sono successo ed insuccesso.<br />
Le istruzioni associate a questi stadi sono <em>COMMIT</em> e <em>ROLLBACK</em>.<br />
In caso di <em>COMMIT</em> tutti i cambiamenti effettuati all&#8217;interno del database diventano permanenti.<br />
In caso di <em>ROLLBACK</em>, tutti i cambiamenti effettuati vengono annullati. Tipicamente, un&#8217;istruzione di <em>ROLLBACK</em> viene utilizzata in caso di errore durante lo svolgimento delle operazioni della Transazione per riportare il database allo stato iniziale.<br />
Concludere una Transazione con uno di questi due metodi significa liberare le risorse allocate, rendendo più efficiente e veloce il database.<br />
C&#8217;è un&#8217;ulteriore parametro passabile ad entrambe le istruzioni, questo è <em>RETAIN</em>.<br />
Se viene aggiunta questa voce ad una delle due istruzioni, la Transazione non viene terminata, ma vengono invece registrate (o annullate) tutte le modifiche effettuate dall&#8217;avvio a quel momento. La Transazione rimane dunque aperta, passibile di altre istruzioni SQL comprese nuove <em>COMMIT RETAIN</em> o <em>ROLLBACK RETAIN</em>. E&#8217; facile capire anche come il lanciare immediatamente dopo un comando comprensivo della voce <em>RETAIN</em> un&#8217;istruzione di tipo <em>COMMIT</em> o <em>ROLLBACK</em> non produca effetto alcuno se non il terminare la Transazione in corso.</p>
<p><strong>Utilizzare le Transazioni in PHP</strong></p>
<p>Il nostro obiettivo è quello di creare un metodo che consenta alla nostra classe di operare con le Transazioni.<br />
Il supporto che PHP fornisce per gestire le Transazioni di Firebird si basa sul concetto di handle, ed anche se già dovrebbe essere chiaro in quanto parte fondamentale dei precedenti articoli, facciamo un veloce riepilogo : Un handle è un indirizzo di memoria al quale è associata la nostra connessione. In PHP questo indirizzo di memoria viene generalmente registrato all&#8217;interno di una variabile che viene usata ogni qualvolta si vogliono effettuare query sul database.<br />
Il metodo <em>exec_query</em>, presente nella nostra classe infatti necessita (essendo basato sul metodo PHP <em>ibase_query</em>) di due parametri : l&#8217;handle del database e la stringa sql da eseguire.<br />
Per le transazioni, il concetto è lo stesso. Ad ogni Transazione avviata corrisponde un handle, tutte le operazioni che si vorranno effettuare all&#8217;interno di questa dovranno far riferimento al suo handle specifico.<br />
Per comodità definiremo un solo metodo per la gestione di tutte e tre le operazioni che in base ad un parametro definito, avvierà una Transazione, la completerà con una <em>COMMIT</em> o la annullerrà con una <em>ROLLBACK</em>.<br />
Le funzioni che PHP mette a disposizione in merito all&#8217;argomento sono tre : </p>
<ul>
<li><em>ibase_trans</em> : richiede in input gli argomenti della Transazione (vedi Riquadro 2) e l&#8217;handle del database selezionato, mentre restituisce in output l&#8217;handle della transazione.
</li>
<li><em>ibase_commit</em> : dato in input l&#8217;handle della Transazione, effettua il commit e restituisce un valore booleano tra TRUE o FALSE a seconda di successo o insuccesso.
</li>
<li><em>ibase_rollback</em> : dato in input l&#8217;handle della Transazione, effettua il rollback ed in output si comporta alla stessa maniera di ibase_commit.
</li>
</ul>
<p>Organizzando il nostro metodo, potremmo pensare di usare due parametri : il primo denominato <em>$action</em>  che conterrà la descrizione dell&#8217;operazione da svolgere : “start” per l&#8217;avvio di una transazione e “commit” o “rollback” per il termine di questa in uno dei due modi. Il secondo parametro, $tr_id, lo considereremo un “jolly” nel senso che in caso di avvio della Transazione conterrà gli argomenti di questa (si veda sempre il Riquadro 2), mentre per  commit o rollback conterrà l&#8217;handle della Transazione da terminare.<br />
A questo punto mettendo in pratica quanto accennato, il codice del nostro metodo, potrebbe presentarsi come segue :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">FUNCTION</span> transaction <span style="color: #66cc66;">&#40;</span>$action<span style="color: #66cc66;">,</span> $tr_id <span style="color: #66cc66;">=</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#123;</span>
 switch <span style="color: #66cc66;">&#40;</span>$action<span style="color: #66cc66;">&#41;</span>
 <span style="color: #66cc66;">&#123;</span>
  case <span style="color: #ff0000;">&quot;start&quot;</span> :
   $this<span style="color: #66cc66;">-&gt;</span>connect<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
   <span style="color: #993333; font-weight: bold;">RETURN</span> ibase_trans<span style="color: #66cc66;">&#40;</span>$tr_id<span style="color: #66cc66;">,</span> $this<span style="color: #66cc66;">-&gt;</span>Link_ID<span style="color: #66cc66;">&#41;</span>;
   break;
  case <span style="color: #ff0000;">&quot;commit&quot;</span> :
   <span style="color: #993333; font-weight: bold;">RETURN</span> ibase_commit<span style="color: #66cc66;">&#40;</span>$tr_id<span style="color: #66cc66;">&#41;</span>;
   break;
  case <span style="color: #ff0000;">&quot;rollback&quot;</span> :
   <span style="color: #993333; font-weight: bold;">RETURN</span> ibase_rollback<span style="color: #66cc66;">&#40;</span>$tr_id<span style="color: #66cc66;">&#41;</span>;
   break;
  <span style="color: #993333; font-weight: bold;">DEFAULT</span> :
   <span style="color: #993333; font-weight: bold;">RETURN</span> <span style="color: #993333; font-weight: bold;">NULL</span>;
   break;
 <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Tramite il costrutto switch, decido che tipo di operazione effettuare. Il valore restituito dalla funzione dipenderà dall&#8217;operazione selezionata : in caso di “start” sarà l&#8217;handle della Transazione, mentre per gli altri due casi sarà TRUE in caso di successo o FALSE se l&#8217;operazione fallisce.<br />
Se viene indicato in <em>$action</em> un valore diverso dai tre illustrati, la funzione restituisce NULL.<br />
Unica nota è il fatto che per azione uguale a “start” prima di eseguire la funzione <em>ibase_trans</em>, richiamo la funzione <em>$this->connect()</em> vista nel primo articolo, per fare in modo che la proprietà <em>$this->Link_ID</em> della classe sia un database handle effettivo.</p>
<p><strong>Dalla teoria alla pratica</strong></p>
<p>Una volta aggiunto questo nuovo metodo alla nostra classe, possiamo procedere con la creazione di un esempio effettivo.<br />
Struttureremo lo script in modo che presenti una checkbox che consenta di scegliere una fra tre opzioni : in un caso effettuerà un inserimento nella tabella PEOPLE e terminerà con una <em>ROLLBACK</em>, nell&#8217;altro con una <em>COMMIT</em> ed in più aggiungeremo la possibilità di cancellare il record eventualmente inserito (in modo da poter ripetere l&#8217;esempio più volte). Alla fine effettueremo una SELECT sulla tabella e ne visualizzeremo l&#8217;esito in modo da osservare i cambiamenti prodotti dalle nostre operazioni.<br />
La checkbox porterà allo script la variabile <em>$_POST[“selection”]</em> che tramite il costrutto switch presente nello script, selezionerà l&#8217;operazione da svolgere.<br />
Il risultato finale sarà quanto appare nel riquadro 3 : Lo script presenta argomenti trattati nei precenti articoli quali il passaggio di parametri alla query e la stampa in una tabella del result set di una query e che qui non verranno ulteriormente approfonditi, le parti da esaminare a fondo sono quelle in cui viene avviata la Transazione</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #000088;">$tr_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;start&quot;</span><span style="color: #339933;">,</span> IBASE_DEFAULT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>In questo modo assegnamo alla variabile <em>$tr_id</em> l&#8217;handle della transazione e proprio in funzione di questo, la query di inserimento verrà lanciata con questa variabile come parametro di handle :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tr_id</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>Se l&#8217;operazione ha successo, viene effettuata (a seconda della scelta) l&#8217;operazione di rollback o commit che terrà come riferimento sempre <em>$tr_id</em> come handle :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;rollback&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tr_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>o</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;commit&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tr_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Il risultato consentirà di visualizzare il comportamento del database nei due diversi casi : solo per <em>COMMIT</em> il record viene inserito, la modifica non avrà effetto per <em>ROLLBACK</em>.<br />
Un&#8217;ulteriore ed interessante test potrebbe riguardare l&#8217;argomento passato alla Transazione in fase di avvio : se al posto di <em>IBASE_DEFAULT</em> indichiamo <em>IBASE_READ</em> e proviamo ad inserire il record, sia che effettuiamo una commit, sia che effettuiamo una rollback, otteniamo questo errore :<br />
“attempted update during read-only transaction”, ciò conferma ancora di più l&#8217;importanza che ricoprono gli argomenti passati alla Transazione in fase di avvio.<br />
Il risultato finale dopo una <em>COMMIT</em> appare in Figura 1.</p>
<div id="attachment_117" class="wp-caption alignnone" style="width: 406px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2004/12/ib_class_articolo_3-10-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2004/12/ib_class_articolo_3-10-figura1.png" alt="Figura 1" title="ib_class_articolo_3-10-figura1" width="396" height="374" class="size-full wp-image-117" /></a><p class="wp-caption-text">Figura 1</p></div>
<p><strong>Conclusioni</strong></p>
<p>Bene. Abbiamo finito. La nostra classe ora consente di effettuare tutte le operazioni che generalmente si fanno su un database Firebird.<br />
Inutile sottolineare un&#8217;ultima volta come l&#8217;implementazione di tutti i metodi presentati è puramente indicativa. Le potenzialità di un progetto simile sono pressoché infinite. </p>
<p><strong>Riquadro 1 : Le transazioni di “default”</strong></p>
<p>Proviamo a fare una veloce prova sul db di test /home/janet/dbtest.gdb (creato negli scorsi articoli) utilizzando l&#8217;utilissimo tool da linea di comando “isql” presente nella directory di installazione di Firebird (generalmente /opt/interbase/bin), effettuando un inserimento nella tabella PEOPLE seguito da un&#8217;istruzione di <em>ROLLBACK</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>root<span style="color: #000000; font-weight: bold;">@</span>conflitto janet<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #666666; font-style: italic;"># /opt/interbase/bin/isql</span>
Use CONNECT or CREATE DATABASE to specify a database
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> CONNECT <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>janet<span style="color: #000000; font-weight: bold;">/</span>dbtest.gdb USER sysdba PASSWORD masterkey;
Database:  <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>janet<span style="color: #000000; font-weight: bold;">/</span>dbtest.gdb, User: sysdba
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> SELECT PCODE, PNAME, PSURNAME FROM PEOPLE;
&nbsp;
       PCODE PNAME                          PSURNAME
============ ============================== ==============================
&nbsp;
           <span style="color: #000000;">0</span> Vito                           Corleone
           <span style="color: #000000;">1</span> Michael                        Corleone
           <span style="color: #000000;">2</span> Sonny                          Corleone
           <span style="color: #000000;">3</span> Fredo                          Corleone
           <span style="color: #000000;">4</span> Tom                            Hagen
           <span style="color: #000000;">5</span> Peter                          Clemenza
           <span style="color: #000000;">6</span> Kay                            Adams Corleone
&nbsp;
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> INSERT INTO PEOPLE <span style="color: #7a0874; font-weight: bold;">&#40;</span>PCODE, PNAME, PSURNAME<span style="color: #7a0874; font-weight: bold;">&#41;</span> VALUES <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">6</span>, <span style="color: #ff0000;">'Luca'</span>, <span style="color: #ff0000;">'Brasi'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> SELECT PCODE, PNAME, PSURNAME FROM PEOPLE;
&nbsp;
       PCODE PNAME                          PSURNAME
============ ============================== ==============================
&nbsp;
           <span style="color: #000000;">0</span> Vito                           Corleone
           <span style="color: #000000;">1</span> Michael                        Corleone
           <span style="color: #000000;">2</span> Sonny                          Corleone
           <span style="color: #000000;">3</span> Fredo                          Corleone
           <span style="color: #000000;">4</span> Tom                            Hagen
           <span style="color: #000000;">5</span> Peter                          Clemenza
           <span style="color: #000000;">6</span> Kay                            Adams Corleone
           <span style="color: #000000;">6</span> Luca                           Brasi
&nbsp;
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> ROLLBACK;
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> SELECT PCODE, PNAME, PSURNAME FROM PEOPLE;
&nbsp;
       PCODE PNAME                          PSURNAME
============ ============================== ==============================
&nbsp;
           <span style="color: #000000;">0</span> Vito                           Corleone
           <span style="color: #000000;">1</span> Michael                        Corleone
           <span style="color: #000000;">2</span> Sonny                          Corleone
           <span style="color: #000000;">3</span> Fredo                          Corleone
           <span style="color: #000000;">4</span> Tom                            Hagen
           <span style="color: #000000;">5</span> Peter                          Clemenza
           <span style="color: #000000;">6</span> Kay                            Adams Corleone
&nbsp;
SQL<span style="color: #000000; font-weight: bold;">&gt;</span> QUIT;</pre></div></div>

<p>All&#8217;inizio in tabella, effettuando la prima select, osserviamo come siano presenti solamente 6 record. Una volta effettuato l&#8217;inserimento, e rilanciata la select, ci accorgiamo di come il nuovo record inserito esista.<br />
Forzando il <em>ROLLBACK</em> della Transazione, il record inserito sparisce, riportando il database allo stato inziale, come se noi non avessimo effettuato nessun tipo di operazione.<br />
Questo dimostra come pur non avendo dichiarato esplicitamente l&#8217;avvio della Transazione, siamo in grado di controllarne il flusso tramite le istruzioni <em>ROLLBACK</em> e <em>COMMIT</em>.<br />
Un&#8217;altra piccola nota : nel momento in cui viene effettuata una <em>ROLLBACK</em> o una <em>COMMIT</em> sulla Transazione di default, ne viene subito avviata una nuova, a sottolineare come ogni operazione sul database viene obbligatoriamente associata ad una Transazione. E&#8217; questo lo stesso motivo per cui rimanendo nell&#8217;ambiente isql possiamo continuare a lanciare <em>ROLLBACK</em> o <em>COMMIT</em> a rotazione pur non effettuando nessun tipo di operazione : queste istruzioni chiuderanno la Transazione di default e Firebird sistematicamente ne creerà una nuova.</p>
<p><strong>Riquadro 2 : Gli argomenti di ibase_trans</strong></p>
<p>La scelta del parametro <em>trans_args</em> passabile alla funzione <em>ibase_trans</em> va effettuata tra questi valori predefiniti : </p>
<ul>
<li>IBASE_DEFAULT</li>
<li>IBASE_READ</li>
<li>IBASE_WRITE</li>
<li>IBASE_COMMITTED</li>
<li>IBASE_CONSISTENCY</li>
<li>IBASE_CONCURRENCY</li>
<li>IBASE_REC_VERSION</li>
<li>IBASE_REC_NO_VERSION</li>
<li>IBASE_WAIT</li>
<li>IBASE_NOWAIT</li>
</ul>
<p>Ciascuno di questi guida uno specifico comportamento della Transazione.<br />
Purtroppo non esiste nemmeno sul sito ufficiale di PHP una spiegazione specifica su ciascuna singola voce, solo alcune (le più usate) sono abbastanza autoesplicative.<br />
Indicando <em>IBASE_DEFAULT</em> ad esempio, si avvia una Transazione le cui proprietà sono quelle di default ossia access mode <em>READ ONLY</em>, lock resolution <em>NO WAIT</em> ed isolation level <em>SNAPHOT</em>.<br />
Nell&#8217;attesa che il supporto di PHP da questo punto di vista migliori, è necessario sperimentare in ambiente di prova le opzioni che si vogliono utilizzare in modo da non incorrere in spiacevoli inconvenienti.</p>
<p><strong>Riquadro 3 : Test con ROLLBACK e COMMIT</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;html&gt;
&lt;body&gt;
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span>  
 <span style="color: #666666; font-style: italic;">// Inclusione file ib_class </span>
 <span style="color: #b1b100;">include</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ib_class.inc&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #666666; font-style: italic;">// Creazione classe Ibase_DB </span>
 <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ib_class<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;/home/janet/dbtest.gdb&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;SYSDBA&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;masterkey&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;selection&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">&quot;rollback&quot;</span> <span style="color: #339933;">:</span>  
   <span style="color: #000088;">$tr_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;start&quot;</span><span style="color: #339933;">,</span> IBASE_DEFAULT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #990000;">ibase_errmsg</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #666666; font-style: italic;">// Test Rollback</span>
   <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;INSERT INTO PEOPLE (pcode, pname, psurname) VALUES (?, ?, ?)&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #666666; font-style: italic;">// Definisco i parametri</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Luca&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Brasi&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   
   <span style="color: #666666; font-style: italic;">// Esecuzione query </span>
   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tr_id</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
    <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo </span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">else</span>
    <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;rollback&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tr_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">&quot;commit&quot;</span> <span style="color: #339933;">:</span>    
   <span style="color: #000088;">$tr_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;start&quot;</span><span style="color: #339933;">,</span> IBASE_DEFAULT<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #666666; font-style: italic;">// Test Commit</span>
   <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;INSERT INTO PEOPLE (pcode, pname, psurname) VALUES (?, ?, ?)&quot;</span><span style="color: #339933;">;</span>  
   <span style="color: #666666; font-style: italic;">// Definisco i parametri</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Luca&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Brasi&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   
   <span style="color: #666666; font-style: italic;">// Esecuzione query </span>
   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$tr_id</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
    <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo </span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">else</span>
    <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">transaction</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;commit&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$tr_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">&quot;delete&quot;</span><span style="color: #339933;">:</span> 
   <span style="color: #666666; font-style: italic;">// Cancello gli eventuali inserimenti</span>
   <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;DELETE FROM PEOPLE WHERE pcode = ?&quot;</span><span style="color: #339933;">;</span>  
   <span style="color: #666666; font-style: italic;">// Definisco i parametri</span>
   <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">7</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #666666; font-style: italic;">// Esecuzione query </span>
   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
    <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo </span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">default</span> <span style="color: #339933;">:</span> <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span> 
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
&lt;form action=&quot;<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;PHP_SELF&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><span style="color: #000000; font-weight: bold;">?&gt;</span>&quot; method=&quot;post&quot;&gt;
&lt;input type=&quot;radio&quot; name=&quot;selection&quot; value=&quot;rollback&quot;&gt;Inserisci ed effettua rollback (il record non viene inserito)
&lt;br&gt;
&lt;input type=&quot;radio&quot; name=&quot;selection&quot; value=&quot;commit&quot;&gt;Inserisci ed effettua commit (il record viene inserito)
&lt;br&gt;
&lt;input type=&quot;radio&quot; name=&quot;selection&quot; value=&quot;delete&quot;&gt;Cancella il record inserito
&lt;br&gt;
&lt;input type=&quot;submit&quot;&gt;
&lt;/form&gt;
&lt;p&gt;Stato tabella :
&nbsp;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> 
 <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT a.PCODE, a.PNAME, a.PSURNAME FROM PEOPLE a ORDER BY a.PCODE&quot;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #666666; font-style: italic;">// Esecuzione query </span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo </span>
  <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">display_error</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
 <span style="color: #b1b100;">else</span> 
 <span style="color: #009900;">&#123;</span>  
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;table border=&quot;</span><span style="color: #cc66cc;">1</span><span style="color: #0000ff;">&quot;&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// Creo le colonne della tabella</span>
  <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">list</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$colonna</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">=</span><span style="color: #990000;">each</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;th&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$colonna</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/th&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// Creo le righe della tabella</span>
  <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next_record</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;tr&gt;&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$fld</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Num_Fields</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fld</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/tr&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/table&gt;&quot;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
&lt;/body&gt; 
&lt;/html&gt;</pre></div></div>

<p><strong>Allegati</strong></p>
<p>Il file relativo alla classe a questo indirizzo : <a href='http://localhost/miamammausalinux.org/wp-content/uploads/2004/10/ib_class.inc'>ib_class.inc</a>.</p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/">Parte 1: costruzione della classe e implementazione dei metodi base</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/">Parte 2: Gestione dei campi BLOB</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/">Parte 3: Gestione delle Transazioni</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Dicembre 2004/Gennaio 2005.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Una classe PHP per l&#8217;accesso a Firebird &#8211; Parte 2: Gestione dei campi BLOB</title>
		<link>http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/</link>
		<comments>http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/#comments</comments>
		<pubDate>Mon, 01 Nov 2004 12:00:07 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Firebird]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Applicazioni Web]]></category>
		<category><![CDATA[Programmazione]]></category>
		<category><![CDATA[Sviluppo]]></category>

		<guid isPermaLink="false">http://localhost/miamammausalinux.org/?p=66</guid>
		<description><![CDATA[&#160;&#160;&#160;&#160; Nello scorso articolo abbiamo iniziato a costruire una classe PHP per l&#8217;accesso ad un database Firebird. Sulla base di proprietà e metodi specifici abbiamo inziato ad effettuare query ed a navigare nei resultset di queste. Quello che ci apprestiamo a fare ora è entrare nello specifico, costruendo metodi che ci permettano di gestire un [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/firebird.png" alt="firebird" title="firebird" width="100" class="alignnone size-full wp-image-171" />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/php.png" alt="php" title="php" width="100" class="alignnone size-full wp-image-175" /></p>
<p>Nello scorso articolo abbiamo iniziato a costruire una classe PHP per l&#8217;accesso ad un database Firebird. Sulla base di proprietà e metodi specifici abbiamo inziato ad effettuare query ed a navigare nei resultset di queste.<br />
Quello che ci apprestiamo a fare ora è entrare nello specifico, costruendo metodi che ci permettano di gestire un tipo di campo particolare denominato BLOB.<br />
Quanto segue si basa totalmente sulla classe presentata e costruita nello scorso articolo, senza quella base i nuovi metodi implementati non hanno senso.</p>
<p><strong>Panoramica sui campi BLOB</strong></p>
<p>In genere quando si definisce un campo in una tabella bisogna sapere a priori quale dovrà essere la sua dimensione massima. Molte volte però non è possibile stabilire a priori quanti dati dovrà contenere un campo, basti pensare alle note di un&#8217;ordine : come si può stabilire quanto un cliente scriverà all&#8217;interno di queste ? La risposta si trova appunto nei campi BLOB.<br />
Un campo BLOB a differenza di tutte le altre tipologie definibili in un RDBMS ha la caratteristica di essere dimensionato dinamicamente, non viene definita cioè la grandezza del campo in fase di creazione.<br />
In genere campi di questo tipo vengono utilizzati per gestire grandi quantità di dati di grandezza varibile : Immagini bitmap, file audio, file video, capitoli di libri e tantissime altre tipologie.<br />
Proprio a causa di questa particolare attitudine, i campi BLOB non si possono gestire in maniera “comune” tramite operazioni di SELECT o INSERT, ma necessitano di misure particolari sia per la scrittura che per la lettura. Questo perchè non viene registrato direttamente il contenuto del campo all&#8217;interno della tabella, ma solo il suo identificativo, il <em>BLOB_ID</em>. I dati del BLOB vengono registrati in un&#8217;altra area del database, suddivisi in segmenti. Il <em>BLOB_ID</em> rappresenta l&#8217;indirizzo di partenza di questi segmenti.<br />
Questo concetto è spiegato egregiamente in Figura 1.</p>
<div id="attachment_109" class="wp-caption alignnone" style="width: 491px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura1.png" alt="Figura 1" title="ib_class_articolo_2-11-figura1" width="481" height="190" class="size-full wp-image-109" /></a><p class="wp-caption-text">Figura 1</p></div>
<p><strong>Definire un campo BLOB</strong></p>
<p>In Firebird la definizione di un campo BLOB all&#8217;interno di una tabella avviene in questo modo :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;">NOMECAMPO BLOB SUB_TYPE <span style="color: #66cc66;">&lt;</span>tipo subtype<span style="color: #66cc66;">&gt;</span> SEGMENT SIZE <span style="color: #66cc66;">&lt;</span>grandezza<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Questo tipo di sintassi ci permette di dichiarare il nome del campo, il fatto che sia di tipo BLOB, il sottotipo (SUB_TYPE) e la grandezza dei sagmenti ad esso associati (SEGMENT SIZE).<br />
SUB_TYPE rappresenta il sotto-tipo del campo, un valore che descrive la natura del dato in esso contenuto. In firebird ne esistono 9 tipi (da 0 a <img src='http://www.miamammausalinux.org/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> :</p>
<ul>
<li>0</li>
<li>1 o TEXT</li>
<li>2 o BLR</li>
<li>3 o ACL</li>
<li>4 o RANGES </li>
<li>5 o SUMMARY</li>
<li>6 o FORMAT</li>
<li>7 o TRANSACTION_DESCRIPTION</li>
<li>8 o EXTERNAL_FILE_DESCRIPTOR : </li>
</ul>
<p>Una spiegazione completa di ciascuno di questi particolari sottotipi la si può trovare a questo URL :<br />
<a href="http://www.ibphoenix.com/a502.htm">http://www.ibphoenix.com/a502.htm</a><br />
per i nostri esempi noi adotteremo il subtipo <em>TEXT</em>, usato appunto per registrare e manipolare testo. Se non si è certi di quale tipo scegliere, si può non indicare nulla in quanto di default verrà considerato il sottotipo 0 che generalmente viene usato per dati binari o indefiniti.<br />
<em>SEGMENT SIZE</em> rappresenta la grandezza massima che i segmenti del campo BLOB possono assumere. Il valore indicato può arrivare fino a 32767 bytes. Se non si indica il valore di grandezza del segmento, Firebird considera default <em>SEGMENT SIZE</em> 80.<br />
Anche in questo caso sarebbe bene approfondire il concetto di <em>SEGMENT SIZE</em> sulla documentazione ufficiale di Interbase 6.0 nel pdf denominato DataDef.pdf, pagine relative ai campi BLOB (Le pagine dalla 76 in poi). Questa documentazione pur riferendosi ad una versione di Interbase passata (la prima ed unica OpenSource, 6.0) si adatta per i concetti esposti anche a Firebird. La sipuò trovare sul sito ufficiale di Firebird a questo indirizzo :<br />
<a href="http://firebird.sourceforge.net/index.php?op=doc&#038;id=userdoc">http://firebird.sourceforge.net/index.php?op=doc&#038;id=userdoc</a><br />
scaricare e consultare  questa documentazione non è affatto un lavoro in utile, in particolare, relativamente ai campi BLOB, il capitolo 8 del libro “EMBEDDED SQL GUIDE”.<br />
Seppur datata risulta in diverse occasioni assai preziosa. .</p>
<p><strong>Prepararsi al lavoro</strong></p>
<p>Nello scorso articolo avevamo già definito nel database di test una tabella con un campo BLOB :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> PEOPLE <span style="color: #66cc66;">&#40;</span>
    pcode    INTEGER <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    psurname VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">30</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    pname    VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">30</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    pquote   BLOB SUB_TYPE TEXT SEGMENT SIZE <span style="color: #cc66cc;">240</span><span style="color: #66cc66;">,</span>   
    <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>La riga che a noi interessa è chiaramente quella contenente la dichiarazione del campo BLOB :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;">    pquote   BLOB SUB_TYPE TEXT SEGMENT SIZE <span style="color: #cc66cc;">240</span><span style="color: #66cc66;">,</span></pre></div></div>

<p>Questa segnala a Firebird di creare un campo BLOB di sottotipo <em>TEXT</em> (quello che ci interessa memorizzare sono frasi “memorabili”, quindi essenzialmente testo) con segmenti di 240 bytes.<br />
Questo campo ci permetterà di sperimentare le funzioni PHP per la gestione dei BLOB in Firebird.</p>
<p><strong>Utilizzare i campi BLOB in PHP</strong></p>
<p>Ciò che ci interessa implementare nella nostra classe PHP relativamente ai campi BLOB, sono le due operazioni fondamentali : lettura e scrittura.<br />
Come già accennato precedentemente, per reperire un campo BLOB da una tabella non è sufficente effettuare una SELECT su questo e scriverne il contenuto in output semplicemente con una echo, come se si trattasse di un campo qualsiasi (ad esempio <em>VARCHAR</em>).<br />
Se si dovesse procedere in questa maniera, non si riceverebbe alcun errore dal compilatore PHP, ma a video non apparirebbe il testo contenuto nel BLOB, bensì il suo ID, il quale apparendo in forma binaria risulterebbe del tutto incomprensibile.<br />
Quindi procedendo correttamente i passi da svolgere per reperire il contenuto di un campo BLOB diventano i seguenti :</p>
<ul>
<li>Ricavare tramite SELECT il <em>BLOB_ID</em> del campo interessato;</li>
<li>Aprire l&#8217;area di memoria del database identificata dal <em>BLOB_ID</em></em>;</li>
<li>Reperire il contenuto del <em>BLOB</em> da quest&#8217;area per elaborarlo secondo le nostre esigenze;</li>
<li>Chiudere l&#8217;area di memoria in questione.</li>
</ul>
<p>Lo stesso concetto va applicato (anche se in maniera opposta) all&#8217;inserimento, i cui passi possono essere rappresentati come segue :</p>
<ul>
<li>Creare un&#8217;area di memoria nel database;</li>
<li>Inserire in questa i valori relativi al contenuto (Testo o dati binari relativi ad immagini, video etc.);</li>
<li>Registrare l&#8217;ID di quest&#8217;area di memoria nel campo BLOB della tabella;</li>
<li>Chiudere l&#8217;area di memoria.</li>
</ul>
<p>Per effettuare queste due serie di operazioni creeremo due metodi dal nome autoesplicativo : <em>blob_field_in</em> e <em>blob_field_out</em>.</p>
<p>PHP offre le funzioni di gestione dei campi BLOB in Interbase/Firebird, ma purtroppo sul sito ufficiale queste non sono documentate, poco male se si pensa che fino a pocotempo fa non erano nemmeno menzionate !<br />
Un elenco completo delle funzioni disponibili lo si trova qui :<br />
<a href="http://it2.php.net/manual/it/ref.ibase.php">http://it2.php.net/manual/it/ref.ibase.php</a></p>
<p><strong>Reperire valori da un campo BLOB</strong></p>
<p>Dettati i presupposti possiamo inziare a creare un metodo che visualizzi il contenuto di un campo BLOB ricavato dal resultset di una query.<br />
I parametri di cui il nostro metodo avrà bisogno saranno sicuramente il nome del campo interessato ed il formato di uscita dei dati, in modo da poter effettuare una pre-elaborazione dell&#8217;output e velocizzare i tempi di lavorazione.<br />
Partendo dal presupposto che tramite il metodo <em>exec_query</em> (illustrato nel precedente articolo) abbiamo nell&#8217;array Record della nostra classe una riga del resultset della query effettuata, possiamo iniziare a concentrarci sui metodi PHP :<br />
Per prima cosa è necessario reperire il <em>BLOB_ID</em> del nostro campo, la prima funzione che viene in nostro aiuto è <em>ibase_blob_open</em> : a questa va passato semplicemente il valore binario ricavato dalla query per farsi restituire il <em>BLOB_ID</em> relativo. Ora che conosciamo qual&#8217;è l&#8217;indirizzo di memoria dei dati che ci interessano, possiamo iniziare a reperirli tramite la funzione <em>ibase_blob_get</em>. A questa è necessario passare chiaramente il <em>BLOB_ID</em> ed in più la lunghezza in byte di quanti dati si vogliono reperire. La funzione restituirà tanti byte quanti ne sono stati richiesti fino a che non arriverà alla fine del campo, momento in cui il valore restituito diventerà FALSE.<br />
Essendo il valore BLOB diviso in segmenti e non sapendo a priori la grandezza di questi, per effettuare un reperimento preciso useremo un comodo espediente : generiamo un numero casuale tramite la funzione rand e utilizziamo come lunghezza di byte il resto della divisione tra questo numero e 1024. Questo numero non potrà mai superare 1024, di conseguenza ci consentirà di reperire aree dati minori di 1024 bytes (1 Kb).<br />
Seppur questo step possa sembrare superfluo (si potrebbe passare un valore fisso inferiore a 1024 sempre e comunque) è necessario e fondamentale per non sovraccaricare la memoria durante le operazioni di reperimento di grosse moli di dati da campi BLOB&#8230;Provare per credere !<br />
Accodando i vari “pezzi” del nostro BLOB in una variabile potremmo finalmente avere in locale i dati che ci interessano ed operare su di essi per emetterli a seconda del formato d&#8217;uscita richiesto.<br />
Una volta che quanto ci interessa si trova in una variabile locale, possiamo chiudere il BLOB attraverso la funzione <em>ibase_blob_close</em> alla quale va passato solo il <em>BLOB_ID</em> interessato.<br />
I formati d&#8217;uscita potrebbero essere 3 : restituire il dato così come lo si riceve, restituire il dato con i caratteri speciali html convertiti in “escape sequences” per prevenire l&#8217;esecuzione di codice html o anche javascript maligno ed infine restituire il dato formattato per l&#8217;html (quindi con gli “accapo” trasformati in tag <br />), ma sempre con il discorso sicurezza applicato ai caratteri speciali html.<br />
In conclusione il nostro metodo potrebbe presentarsi così :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> blob_field_out<span style="color: #009900;">&#40;</span><span style="color: #000088;">$field_name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$html</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #000088;">$blob_text</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$field_name</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$blob_id</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_blob_open</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$field_name</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$piece</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_blob_get</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_id</span><span style="color: #339933;">,</span> <span style="color: #990000;">rand</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">%</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #000088;">$blob_text</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$piece</span><span style="color: #339933;">;</span>
  <span style="color: #990000;">ibase_blob_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">switch</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$html</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">&quot;s&quot;</span> <span style="color: #339933;">:</span> <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">case</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">||</span> <span style="color: #009900; font-weight: bold;">NULL</span> <span style="color: #339933;">||</span> <span style="color: #009900; font-weight: bold;">FALSE</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$blob_text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">htmlspecialchars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">default</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$blob_text</span> <span style="color: #339933;">=</span> <span style="color: #990000;">nl2br</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">htmlspecialchars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_text</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
 <span style="color: #009900;">&#125;</span>
 <span style="color: #b1b100;">return</span> <span style="color: #000088;">$blob_text</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Tutta la funzione dipende comunque dal fatto che <em>$this->Record[$field_name]</em> sia valorizzato, in caso contrario il valore restituito sarà una stringa vuota.<br />
Il ciclo while serve per accodare i valori reperiti dal campo BLOB all&#8217;interno della variabile <em>$blob_text</em> e fino a che verrà assegnato un valore a <em>$piece</em>, <em>$blob_text</em> continuerà ad incrementarsi.<br />
Il costrutto switch ci consente invece di selezionare il tipo di formato output : passando quindi “s” come secondo parametro al nostro metodo, considereremo il contenuto del BLOB affidabile e così come ci viene restituito, se invece questo non sarà valorizzato (0, NULL o FALSE) restituiremo il tutto “corretto” da eventuali entità html (la funzione <em>htmlspecialchars</em> non fa altro che questo), mentre se il parametro <em>$html</em> un valore qualsiasi diverso da questi oltre ad effettuare un controllo sulle entità html convertiremo anche i caratteri “n” o newline in accapo html ossia “&lt;br&gt;”.</p>
<p><strong>Inserire valori in un campo BLOB</strong></p>
<p>Inserire dei valori BLOB all&#8217;interno di una tabella significa creare un&#8217;area di memoria all&#8217;interno del database, scrivere in questa i dati che ci interessano, registrare il <em>BLOB_ID</em> associato nella tabella interessata e chiudere l&#8217;area di memoria aperta.<br />
Il nostro metodo dovrà richiedere in input due parametri : il primo è il database handle, che rappresenterà l&#8217;indirizzo relativo alla connessione sulla quale stiamo lavorando, il secondo conterrà i dati da inserire nel campo BLOB.<br />
Tramite il metodo PHP <em>ibase_blob_create</em> al quale va passato l&#8217;handle del nostro database reperiremo il <em>BLOB_ID</em> relativo ad una nuova area di memoria creata. Questo prezioso valore ci consentirà di inserire dati all&#8217;interno di quest&#8217;area tramite la funzione <em>ibase_blob_add</em> alla quale passeremo il <em>BLOB_ID</em> e la variabile contenente i dati da registrare. Infine faremo restituire al nostro metodo quanto riceveremo dalla funzione <em>ibase_blob_close</em> , ossia il BLOB_ID da registrare all&#8217;interno del campo della tabella.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> blob_field_in<span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span> <span style="color: #339933;">==</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #000088;">$blob_text</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">is_resource</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$dbh</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">else</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000088;">$blob_id</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_blob_create</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #990000;">ibase_blob_add</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_id</span><span style="color: #339933;">,</span> <span style="color: #000088;">$blob_text</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">return</span> <span style="color: #990000;">ibase_blob_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$blob_id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Se <em>$dbh</em> è valorizzato (non deve essere nullo e deve essere una risorsa), allora verrà usato questo handle per svolgere le operazioni, in caso contrario verrà richiamata la funzione connect.</p>
<p><strong>Dalla teoria alla pratica</strong></p>
<p>Una volta aggiunti questi due nuovi metodi alla nostra classe, possiamo procedere con la creazione di un esempio effettivo di inserimento di un record contenente un BLOB e la visualizzazione di questo.<br />
Il codice contenuto nel Riquadro 1 riassume tutti i concetti esposti sinora.<br />
Si parte con l&#8217;inclusione del file classe, la creazione di questa mediante il suo costruttore, e si inserisce tramite i parametri il nuovo record all&#8217;interno della tabella.<br />
Particolare attenzione va posta alla riga</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">blob_field_in</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$blob</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>che aggiunge alla lista dei parametri anche il <em>BLOB_ID</em> ricavato dalla funzione <em>blob_field_in</em> che ci siamo costruiti, a questa vengono passati due parametri : 0 che rappresenta una connessione vuota ed obbliga quindi la funzione a stabilirne una nuova e $blob ossia la variabile che contiene il testo (con accapo) da inserire nel nostro BLOB.<br />
Una volta eseguito con successo l&#8217;inserimento vengono proposti i due tipi di visualizzazione del risultato : nel primo il campo viene presentato così come è estratto dalla tabella, e come si può vedere dalla Figura 2, ciò che appare è assolutamente incomprensibile, nel secondo grazie alla riga</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">blob_field_out</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PQUOTE&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Viene visualizzato il risultato corretto (Figura 3), ossia quanto restituito dalla funzione <em>blob_field_out</em>, alla quale abbiamo passato il nome del campo interessato “PQUOTE” e 1 per indicare di convertire gli accapo in “&lt;br&gt;”.</p>
<div id="attachment_110" class="wp-caption alignnone" style="width: 286px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura2.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura2.png" alt="Figura 2" title="ib_class_articolo_2-11-figura2" width="276" height="233" class="size-full wp-image-110" /></a><p class="wp-caption-text">Figura 2</p></div>
<div id="attachment_111" class="wp-caption alignnone" style="width: 597px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura3.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2004/11/ib_class_articolo_2-11-figura3.png" alt="Figura 3" title="ib_class_articolo_2-11-figura3" width="587" height="270" class="size-full wp-image-111" /></a><p class="wp-caption-text">Figura 3</p></div>
<p><strong>Conclusioni</strong></p>
<p>Ancora una volta ci tengo ad indicare come l&#8217;implementazione di tutti i metodi presentati è puramente indicativa. Si può fare tutto e più di tutto con questi strumenti che l&#8217;OpenSource ci mette a disposizione, questa è solo una delle tante vie.<br />
In questo secondo articolo abbiamo cercato di capire il concetto di BLOB e di implementare metodi che ne consentano l&#8217;utilizzo, nel prossimo parleremo di transazioni, cercando anche in questo caso di creare metodi specifici che ci consentano di lavorare al meglio spremendo Firebird fino all&#8217;ultimo bit.</p>
<p><strong>Riquadro 1 : Inserimento di un campo BLOB, visualizzazione scorretta e corretta</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;html&gt;
&lt;body&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span>
 <span style="color: #666666; font-style: italic;">// Inclusione file ib_class</span>
 <span style="color: #b1b100;">include</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ib_class.inc&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Creazione classe db</span>
 <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ib_class<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;/home/janet/dbtest.gdb&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;SYSDBA&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;masterkey&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Inserimento BLOB</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Stringa sql</span>
 <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;INSERT INTO PEOPLE (PCODE, PNAME, PSURNAME, PQUOTE)  VALUES (?, ?, ?, ?)&quot;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Definizione variabile BLOB (con caratteri accapo)</span>
 <span style="color: #000088;">$blob</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;It made me think of what you once told me:n&quot;</span>In five years the Corleone family will be completely legitimate<span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;n
That was seven years ago.&quot;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Passaggio parametri</span>
 <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Kay&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Adams Corleone&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">blob_field_in</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$blob</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Esecuzione query</span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">else</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Inserimento blob completato con successo !&lt;p&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Stringa sql</span>
  <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT a.PNAME, a.PQUOTE FROM PEOPLE a&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Visualizzazione senza utilizzo di blob_field_out</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;p&gt;&lt;i&gt;Senza &lt;b&gt;blob_field_out&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Esecuzione query</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">else</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;table border=&quot;</span><span style="color: #cc66cc;">1</span><span style="color: #0000ff;">&quot;&gt;n&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;th&gt;Nome&lt;/th&gt;&lt;th&gt;Frase memorabile&lt;/th&gt;n&quot;</span><span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #666666; font-style: italic;">// Creo le righe della tabella</span>
   <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next_record</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;tr&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;PNAME&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;PQUOTE&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/tr&gt;n&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/table&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Visualizzazione con blob_field_out</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;p&gt;Con &lt;i&gt;&lt;b&gt;blob_field_out&lt;/b&gt;&lt;/i&gt;&lt;br&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Esecuzione query</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">else</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;table border=&quot;</span><span style="color: #cc66cc;">1</span><span style="color: #0000ff;">&quot;&gt;n&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;th&gt;Nome&lt;/th&gt;&lt;th&gt;Frase memorabile&lt;/th&gt;n&quot;</span><span style="color: #339933;">;</span>
&nbsp;
   <span style="color: #666666; font-style: italic;">// Creo le righe della tabella</span>
   <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next_record</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;tr&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;PNAME&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">blob_field_out</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;PQUOTE&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/tr&gt;n&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/table&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
 <span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p><strong>Allegati</strong></p>
<p>Il file relativo alla classe a questo indirizzo : <a href='http://localhost/miamammausalinux.org/wp-content/uploads/2004/10/ib_class.inc'>ib_class.inc</a>.</p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/">Parte 1: costruzione della classe e implementazione dei metodi base</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/">Parte 2: Gestione dei campi BLOB</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/">Parte 3: Gestione delle Transazioni</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Novembre 2004.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Una classe PHP per l&#8217;accesso a Firebird &#8211; Parte 1: costruzione della classe e implementazione dei metodi base</title>
		<link>http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/</link>
		<comments>http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/#comments</comments>
		<pubDate>Fri, 01 Oct 2004 11:30:44 +0000</pubDate>
		<dc:creator>Raoul Scarazzini</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Firebird]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programmazione]]></category>
		<category><![CDATA[Applicazioni Web]]></category>
		<category><![CDATA[Sviluppo]]></category>

		<guid isPermaLink="false">http://localhost/miamammausalinux.org/?p=56</guid>
		<description><![CDATA[&#160;&#160;&#160;&#160; Nell&#8217;esteso panorama degli RDBMS (Relational Database Management System) si sta pian piano ritagliando una fetta di mercato un progetto giovane, ma già molto maturo : Firebird. Nato da una costola del più famoso Interbase della Borland, FireBird rappresenta un&#8217;ottimo punto di partenza per quanti vogliono impementare soluzioni database stabili ed efficenti. Cercheremo in questa [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/firebird.png" alt="firebird" title="firebird" width="100" class="alignnone size-full wp-image-171" />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.miamammausalinux.org/wp-content/uploads/2009/01/php.png" alt="php" title="php" width="100" class="alignnone size-full wp-image-175" /></p>
<p>Nell&#8217;esteso panorama degli RDBMS (Relational Database Management System) si sta pian piano ritagliando una fetta di mercato un progetto giovane, ma già molto maturo : Firebird.<br />
Nato da una costola del più famoso Interbase della Borland, FireBird rappresenta un&#8217;ottimo punto di partenza per quanti vogliono impementare soluzioni database stabili ed efficenti.<br />
Cercheremo in questa serie di articoli di imparare ad accedere a questo motore per database da PHP, costruendo, sulla base della programmazione ad oggetti, una classe di accesso personalizzata che chiameremo ib_class.<br />
L&#8217;ideale, per essere subito operativi, è che nel sistema su cui si lavorerà ci sia installato il motore per database Firebird (la versione attuale e consigliata è la 1.0.3), un webserver (per esempio Apache, 1.3.x o 2.x è indifferente) che supporti Php (4.3.x) e che lo stesso PHP sia compilato con supporto Interbase (e quindi Firebird).</p>
<p><strong>Prima di iniziare</strong></p>
<p>Quella che segue è una breve panoramica su ciò che è la programmazione ad oggetti, su ciò che sono le classi, e su come vengono implementate ed utilizzate in PHP. Essendo l&#8217;obiettivo primario di questo articolo creare una classe PHP specifica, se si desidera approfondire gli argomenti in questione si può far riferimento al testo “Object Oriented Programming – Guida completa” edito da Apogeo per quanto riguarda lo studio della programmazione ad oggetti, mentre all&#8217;indirizzo <a href="http://it.php.net/oop">http://it.php.net/oop</a>  per trovare spiegazioni ed esempi inerenti la programmazione ad oggetti in PHP.<br />
Inoltre non dimentichiamoci mai del buon vecchio google (<a href="http://www.google.com">www.google.com</a>) per effettuare qualsiasi tipo di ricerca tecnica.</p>
<p><strong>OOP : Object Oriented Programming.</strong></p>
<p>I concetti di classe ed oggetto (o istanza) sono alla base della programmazione ad oggetti (OOP, Object Oriented Programming). Una classe rappresenta l&#8217;astrazione di un oggetto mentre un oggetto è istanza di una classe : Creare un oggetto significa istanziare una classe.<br />
Una struttura dati è definita classe quando racchiude in se delle variabili (denominate proprietà o attributi) e le funzioni per la manipolazione di queste (denominate metodi).<br />
E&#8217; importante che la struttura dati di una classe sia trasparente per chi la utilizza : si opererà su questa solo tramite i metodi in essa definiti, quindi sarà necessario conoscere come questi operano e quale è la loro funzione, non come sono stati implementati. In questo modo si garantisce che la classe diventi fruibile non solo da chi l&#8217;ha costruita, bensì da tutti coloro che conoscono come questa funziona e cosa fa.</p>
<p><strong>Panoramica sulle classi in PHP.</strong></p>
<p>PHP è un linguaggio procedurale che però supporta il paradigma della programmazione orientata agli oggetti, proprio per questo possiede una serie di parole chiave necessarie ad implementare classi.<br />
Una classe in PHP viene creata tramite la parola chiave class e nel corpo della sua dichiarazione si trovano tutte le variabili (proprietà) e le funzioni (metodi) che ne descrivono l&#8217;implementazione.<br />
Le proprietà di una classe vengono dichiarate tramite la parola chiave var mentre per i metodi viene usata la parola chiave function.<br />
Per poter accedere alle funzioni e alle variabili interne di una classe, viene usata la pseudo-variabile $this. Questo perchè, in fase di progettazione, non si conosce il nome con cui la classe verrà istanziata all&#8217;interno dei vari programmi. Questa pseudo-variabile può essere quindi letta come “questo oggetto”, this appunto.<br />
Per scorrere proprietà e metodi di un oggetto viene usato l&#8217;operatore “->” che consente, un pò come succede nello scorrimento delle directory tramite l&#8217;operatore “/” di reperire un valore associato ad un percorso : se volessi accedere al file file.txt sotto la cartella /files dovrei far riferimento a questo così : /files/file.txt, negli oggetti la sintassi per accedere ai dati richiama questo concetto : <em>$this->nomeproprietà</em> per le proprietà e <em>$this->nomemetodo()</em> per i metodi.<br />
E&#8217; da notare come la variabile si chiami <em>$this->nomeproprietà</em>, e non <em>$this->$nomeproprietà</em>, pur essendo questa dichiarata come <em>var $nomeproprietà</em> : ciò accade perchè le variabili in PHP vanno scritte con un unico simbolo dollaro.<br />
Come ultima cosa è necessario far notare che, al di fuori della classe stessa, non è mai buona norma assegnare dei valori alle prioprietà di un oggetto, è molto meglio creare dei metodi che effettuino questi assegnamenti.<br />
In PHP 5 è stato introdotto un sistema per evitare che le proprietà di un oggetto vengano modificate all&#8217;esterno di questo : dichiarando una variabile con la parola chiave private anzichè var.<br />
Visto che implementeremo la nostra classe con la versione 4 di PHP, per il momento consideriamo quanto detto solo a livello teorico, cercando di non assegnare direttamente i valori alle proprietà.</p>
<p><strong>Il costruttore, questo sconosciuto</strong></p>
<p>Se tra i metodi dichiarati all&#8217;interno di una classe ne esiste uno con il nome uguale a questa, esso viene chiamato costruttore. Il costruttore viene invocato ogni volta che un&#8217;istanza della classe viene creata ed ha il compito di inizializzare le proprietà del nucoo oggetto. In PHP ciò avviene tramite la parola chiave new :<br />
<em>$nomeoggetto = new nomeclasse();</em><br />
Se non esiste un costruttore, new istanzierà solamente la classe e sarà necessario che ogni parametro abbia dei valori di default.<br />
Una volta creato l&#8217;oggetto, le proprietà di questo saranno accessibili in questo modo <em>$nomeoggetto->nomeproprietà</em> ed i metodi con <em>$nomeoggetto->nomemetodo()</em><br />
Non è obbligatorio avere un costruttore all&#8217;interno di una classe, ma questo metodo è talmente utile da non poterne fare a meno.<br />
Per creare una classe che si rispetti quindi, si fa presto a capire come il primo metodo da implementare sia il costruttore.</p>
<p><strong>Prepariamoci al lavoro</strong></p>
<p>Ora che abbiamo introdotto tutti gli argomenti che tratteremo nel corso dell&#8217;articolo, siamo pronti per iniziare a lavorare.<br />
Si può partire analizzando quali dovranno essere le funzionalità della nostra classe in base alle operazioni che dovrà svolgere : essendo una classe per l&#8217;accesso ad un database, sicuramente dovrà consentirci di stabilire una connessione, di effettuare query sulle tabelle e di navigare all&#8217;interno dei risultati delle nostre interrogazioni. E questo solo per cominciare.<br />
E&#8217; facile intuire come ad ogni funzionalità indicata, dovrà corrispondere un metodo.<br />
Ciascuno di questi metodi dovrà basarsi sulle funzioni che PHP mette a disposizione per l&#8217;accesso ad Interbase/Firebird. Un elenco completo di queste funzioni lo si può trovare sul sito ufficiale di PHP, all&#8217;indirizzo <a href="http://it.php.net/manual/it/ref.ibase.php">http://it.php.net/manual/it/ref.ibase.php</a>.<br />
Quello che dovremo fare, per iniziare, sarà realizzare quattro metodi base :<br />
Un metodo che consenta a chi opera con la classe di istanziarla : dovremo creare cioè il costruttore, partendo dal presupposto che questo metodo dovrà inizializzare le proprietà dell&#8217;oggetto ed avere lo stesso nome della classe.<br />
Un metodo che permetta di connettersi ad un database Firebird basato sulla funzione <em>ibase_connect</em>;<br />
Un metodo che consenta di effettuare delle query. La funzione che ci verrà in aiuto a questo punto sarà <em>ibase_query</em>;<br />
Un ultimo metodo che permetta di operare sui resultset delle query, di scorrere cioè all&#8217;interno dei risultati in modo da poterli presentare nei nostri programmi;<br />
E&#8217; chiaro che questi sono i metodi base, nella stesura di questi necessiteremo di crearne degli altri “minori”, sino ad ottenere una classe pronta per essere usata negli accessi a database Interbase/Firebird.<br />
Per concludere, cercheremo di sviluppare un esempio che acceda ad un database di test (la cui creazione è illustrata nel riquadro1) e che sfrutti tutti i metodi sinora illustrati.<br />
Bene, pronti ? Via !</p>
<p><strong>Creiamo il file</strong></p>
<p>Partendo dal presupposto che la classe si chiamerà ib_class creiamo un file denominato ib_class.inc che contenga l&#8217;intestazione della nostra classe insieme alle prime proprietà essenziali :  il nome host, che identifica appunto l&#8217;Host presso il quale “alloggia” il nostro db, il percorso (path) del database insieme allo username ed alla password di accesso, il Set di caratteri, il numero di buffers ed il dialetto sql usato dal server :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> ib_class <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Host</span>          <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// Host (anche macchina remota)</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Database</span>      <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// Database (file con path)</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$User</span>          <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// Utente</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Password</span>      <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// Password</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Charset</span>       <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// Set di caratteri</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Buffers</span>       <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>       <span style="color: #666666; font-style: italic;">// Numero di buffers</span>
<span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$Dialect</span>       <span style="color: #339933;">=</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span>       <span style="color: #666666; font-style: italic;">// Dialetto SQL</span>
&nbsp;
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Quanto sopra può essere considerato come la vera base della nostra classe. Queste proprietà non a caso rappresentano i dati da passare alla funzione ibase_connect per effettuare la connessione al database che vedremo più avanti.<br />
Ora si può procedere con la creazione di tutti gli altri metodi (e proprietà) specifici, il risultato finale sarà quanto appare nel file ib_class.inc contenuto nel CD, ma chiaramente procedere passo per passo aiuterà a capire meglio i concetti.</p>
<p><strong>Istanziare la classe tramite il costruttore</strong></p>
<p>Il nostro costruttore non dovrà fare altro che assegnare i valori che gli vengono passati dal chiamante (tramite la funzione new) alle proprietà del nostro oggetto.<br />
Il metodo dovrà dichiarare i parametri che gli devono essere passati in input (che rispecchiano le proprietà sino ad ora dichiarate della nostra classe) e tramite l&#8217;ausilio della pseudo-variabile $this effettuare dei semplici assegnamenti.<br />
Ecco come potrebbe apparire :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> ib_class <span style="color: #009900;">&#40;</span><span style="color: #000088;">$Host</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Database</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Charset</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Buffers</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Dialect</span><span style="color: #339933;">,</span> <span style="color: #000088;">$User</span><span style="color: #339933;">,</span> <span style="color: #000088;">$Password</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Host</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Host</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Database</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Database</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Charset</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Charset</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Buffers</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Buffers</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Dialect</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Dialect</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">User</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$User</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Password</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$Password</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Un esempio di come si potrà creare un istanza del nostro oggetto in uno script è quello che segue :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ib_class<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;/home/janet/dbtest.gdb&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;SYSDBA&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;masterkey&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>In questo modo, viene istanziata la classe ib_class nella variabile $db. Essa verrà inizializzata con i valori relativi al database di test che abbiamo creato seguendo quanto spiegato nel riquado 1. L&#8217;istanza della classe (il nostro oggetto) sarà da qui in avanti rappresentata dalla variabile $db.<br />
Piccola considerazione : è facile capire come, dichiarando $db come variabile di sessione in questo modo :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span>“db”<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$db</span><span style="color: #339933;">;</span></pre></div></div>

<p>non avremo bisogno ogni qualvolta ci servirà il nostro oggetto, di reistanziare la classe script per script. Potremo garantire così, tramite la propagazione delle sessioni, di avere in ogni script il nostro oggetto istanziato correttamente. Interessante no ?</p>
<p><strong>Connettersi ad un database Firebird</strong></p>
<p>Ogni volta che si stabilisce una connessione con Firebird (ed in genere con tutti gli RDBMS) a questa viene assegnato un&#8217;indirizzo di memoria, il suo handle. Tutte le iterazioni con il database (query, transazioni etc.) andranno effettuate utilizzando un handle specifico.<br />
Quello che a noi interessa ottenere è il valore relativo al link di una connessione e registrarlo nel nostro oggetto in una nuova proprietà, denominata <em>$this->Link_ID</em>.<br />
La funzione PHP che consente di stabilire una connessione con un database Firebird è ibase_connect : Questa funzione necessita in input dei dati relativi al database (altro non sono che le proprietà che abbiamo già dichiarato del nostro oggetto) ed in caso di successo restituisce l&#8217;handle della connessione.<br />
Il metodo che andremo a dichiarare semplicemente eseguirà la funzione ibase_connect con i parametri del nostro oggetto e assegnerà l&#8217;handle restituito da questa funzione alla proprietà Link_ID.<br />
Il valore restituito dal metodo sarà vero o falso, a seconda dell&#8217;esito della funzione  ibase_errmsg che a sua volta restitusce (se esiste) il testo del messaggio di errore.<br />
A livello di codice, il nostro metodo sarà così strutturato :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> connect<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span> <span style="color: #339933;">=</span> <span style="color: #339933;">@</span><span style="color: #990000;">ibase_connect</span><span style="color: #009900;">&#40;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Host</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;:&quot;</span> <span style="color: #339933;">.</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Database</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">User</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Password</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Charset</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Buffers</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Dialect</span><span style="color: #339933;">,</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Role</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #666666; font-style: italic;">// Se c'è errore allora metto il messaggio in Error e ritorno FALSE</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_errmsg</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">return</span> <span style="color: #990000;">ibase_errmsg</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #009900; font-weight: bold;">FALSE</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><em>ibase_connect</em> automaticamente controlla se esiste già un link oppure ne va creato uno nuovo e lo restituisce in output. In questi termini il nostro metodo potrà essere invocato più volte di fila senza che necessariamente stabilisca per ogni esecuzione una nuova connessione. Come si può intuire, questa funzionalità favorisce il basso traffico di rete (e quindi la maggiore velocità).<br />
Da notare il carattere “@” che precede la chiamata alla funzione <em>ibase_connect</em>. Questo indica al motore PHP di non visualizzare errori o warnings in uscita dalla funzione. Ciò è molto utile se si personalizza la gestione degli errori, come abbiamo fatto noi, assegnando alla nuova proprietà <em>$this->Error</em> del nostro oggetto il valore di uscita della funzione <em>ibase_errmsg</em>. In questo modo potremo decidere quando e come far apparire gli eventuali messaggi di errore, senza generare immotivati timori negli utilizzatori dei nostri programmi <img src='http://www.miamammausalinux.org/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p><strong>Effettuare delle query</strong></p>
<p>Il metodo per l&#8217;esecuzione delle query diverrà essenziale per qualsiasi operazione ci troveremo a fare. Proprio per questo è necessario porre particolare cura nella sua implementazione.<br />
La funzione PHP da tenere come riferimento è <em>ibase_query</em>. Per essere eseguita con successo, questa necessita dell&#8217;handle del database e di una valida stringa sql. Se ha successo e vi sono righe nel risultato (come si ha ad esempio con le query SELECT), restituisce un identificatore di risorsa, mentre se ha successo ma non ci sono righe risultato, restituisce semplicemente TRUE. In caso di fallimento il valore restituito sarà FALSE.<br />
Il concetto di identificatore di risorsa, non si scosta molto da quello di handle : esso rappresenta infatti la parte di memoria riservata al resultset (l&#8217;insieme dei valori risultanti da una query di tipo SELECT) generato da una query.<br />
Il nostro metodo deve eseguire queste operazioni :<br />
Controllo esistenza di una connessione<br />
Esecuzione della query<br />
Controllo esistenza di un resultset e settaggio della nuova proprietà <em>$this->Query_ID</em> con il valore dell&#8217;identificatore di risorsa.<br />
Restituzione del valore “vero” o “falso” a seconda dell&#8217;esito della query.<br />
I parametri che il nostro metodo riceverà in input saranno due : il database handle, <em>$dbh</em> e la stringa sql da eseguire, <em>$query_string</em>. E&#8217; da notare come nella dichiarazione della variabile <em>$dbh</em> venga ad essa assegnato un valore di default, ciò risulterà molto utile nella verifica della validità che viene effettuata all&#8217;inizio della funzione.<br />
Se <em>$dbh</em> è valorizzato (non deve essere nullo e deve essere una risorsa), allora verrà usato questo handle per svolgere le operazioni, in caso contrario verrà richiamata la funzione connect. Passare un handle diverso da quello di default, tornerà utile quando in futuro parleremo di transazioni.<br />
Esaminiamo insieme il codice di questo metodo :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> exec_query<span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">is_resource</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$dbh</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">else</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #990000;">array_unshift</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span><span style="color: #339933;">,</span> <span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span> <span style="color: #339933;">=</span> <span style="color: #339933;">@</span><span style="color: #990000;">call_user_func_array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ibase_query&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span><span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Row</span> <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// La query e' andata a buon fine, setto la variabile Query_Sql della classe ...</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Sql</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$query_string</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// ...Azzero i parametri...</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// ...E se non e' una operazione di modifica creo i metadata</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">&quot;INSERT&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;&amp;</span>
      <span style="color: #009900;">&#40;</span><span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">&quot;UPDATE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;&amp;</span>
      <span style="color: #009900;">&#40;</span><span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">&quot;CREATE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">&amp;&amp;</span>
      <span style="color: #009900;">&#40;</span><span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtoupper</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">&quot;DELETE&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">metadata</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Se c'è errore allora metto il messaggio in Error e ritorno FALSE</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_errmsg</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">return</span> <span style="color: #990000;">ibase_errmsg</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #009900; font-weight: bold;">FALSE</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Dopo aver effettuato il controllo sul database handle già descritto, particolare attenzione va posta verso le due righe</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"> <span style="color: #990000;">array_unshift</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Link_ID</span><span style="color: #339933;">,</span> <span style="color: #000088;">$query_string</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span> <span style="color: #339933;">=</span> <span style="color: #339933;">@</span><span style="color: #990000;">call_user_func_array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ibase_query&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Queste fanno riferimento alla nuova proprietà <em>$this->Query_Params</em> del nostro oggetto, un array che contiene i parametri che la funzione <em>ibase_query</em>richiede in input.<br />
array_unshift inserisce uno o più elementi all&#8217;inizio di un array, mentre <em>call_user_func_array</em> passa come parametri ad una funzione indicata i valori presenti in un array. Questo significa che se <em>$this->Query_Params</em> è vuota, ad <em>ibase_query()</em><em> saranno passati solamente due parametri (handle e stringa sql), mentre nel caso contrario tutti i valori presenti in <em>$this->Query_Params</em> verranno passati a ibase_query nell&#8217;ordine in cui sono presenti nell&#8217;array.<br />
Per spiegare il funzionamento di queste due righe, consideriamo questa query che vuole estrarre tutti i record della tabella PEOPLE che abbiano PSURNAME uguale a “Corleone” :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> “SELECT a<span style="color: #339933;">.*</span> FROM PEOPLE WHERE a<span style="color: #339933;">.</span>PSURNAME <span style="color: #339933;">=</span> ?”<span style="color: #339933;">;</span>
<span style="color: #990000;">ibase_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #339933;">,</span> “Corleone”<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>anzichè scrivere direttamente</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> “SELECT a<span style="color: #339933;">.*</span> FROM PEOPLE WHERE a<span style="color: #339933;">.</span>PSURNAME <span style="color: #339933;">=</span> <span style="color: #0000ff;">'Corleone'</span>”<span style="color: #339933;">;</span>
<span style="color: #990000;">ibase_query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$dbh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>abbiamo indicato il carattere “?” al posto della stringa effettiva fra apici e nel richiamare la procedura <em>ibase_query</em> non abbiamo passato come parametri solamente l&#8217;hanlde e la stringa sql, ma anche “Corleone”.<br />
Applicando questi concetti al nostro oggetto, consideriamo un nuovo metodo denominato <em>add_param();</em> il cui scopo è quello di accodare i parametri all&#8217;interno dell&#8217;array <em>$this->Query_Params</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> add_param<span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_Params</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$param</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>e realizziamo l&#8217;esempio sopracitato :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> “SELECT a<span style="color: #339933;">.*</span> FROM PEOPLE WHERE a<span style="color: #339933;">.</span>PSURNAME <span style="color: #339933;">&lt;&gt;</span> ?”<span style="color: #339933;">;</span>
<span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span>“Corleone”<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Una volta eseguita la query con la funzione <em>ibase_query</em>, se <em>$this->Query_ID</em> viene valorizzato, e quindi la query ha avuto esito positivo, vengono settate le nuove proprietà <em>$this->Row</em> (che rappresenta il numero di riga corrente) e <em>$this->Query_Sql</em> (contenente il codice sql eseguito) ed infine viene azzerato l&#8217;array dei parametri.<br />
Per concludere, se l&#8217;istruzione sql è una SELECT,  viene richiamata la funzione <em>$this->metadata()</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> metadata<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #000088;">$c</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$campo</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_field_info</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span><span style="color: #339933;">,</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$campo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$campo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;relation&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$campo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;relation&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;length&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$campo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;length&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;type&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$campo</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;type&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;index&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$c</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$c</span><span style="color: #339933;">++;</span>
 <span style="color: #009900;">&#125;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #339933;">=</span><span style="color: #000088;">$info</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Num_Fields</span><span style="color: #339933;">=</span><span style="color: #990000;">ibase_num_fields</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #666666; font-style: italic;">// L'array viene anche restituito</span>
 <span style="color: #b1b100;">return</span> <span style="color: #000088;">$info</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Il cui scopo è quello di creare l&#8217;array associativo <em>$this->Fields_Info</em></em> con le proprietà dei campi della tabella risulato attraverso la funzione <em>ibase_field_info()</em>, la quale, richiamata per ogni campo, restituisce un array con informazioni relative a questo nella forma name, alias, relation, length e type.<br />
<em>$this->metadata()</em> assegna anche alla nuova proprietà <em>Num_Fields</em> dell&#8217;oggetto il risultato della funzione <em>ibase_num_fields()</em> che restituisce il numero di campi della tabella risultato.<br />
Infine <em>exec_query</em> controlla che non vi siano errori nello stesso identico sistema di connect, restituendo TRUE o FALSE a seconda del valore restituito da <em>ibase_errmsg()</em>.</p>
<p><strong>Operare sui resultset delle query</strong></p>
<p>Prima di addentrarci nel primo esempio effettivo di utilizzo della nostra classe è necessario capire come fare a muoversi all&#8217;interno di un resultset restituito da una query.<br />
La funzione PHP che ci viene in aiuto in questo caso è <em>ibase_fetch_row</em>. Questa funzione necessita in input dell&#8217;identificatore di risorsa relativo ad una query eseguita e restituisce un array con struttura <em>indicecampo->valore</em>. Il primo passo da compiere quindi è creare una proprietà di tipo array nel nostro oggetto denominata Record che servirà a contenere l&#8217;associazione restituita da <em>ibase_fetch_row</em>.<br />
Ma noi vogliamo di più.<br />
Oltre a questa associazione ne vogliamo creare un&#8217;ulteriore di tipo <em>nomecampo->valore</em>, in questo modo non saremo costretti a ricordarci quale sia l&#8217;indice di un campo per conoscerne il valore, basterà sapere il nome di questo ed accederci tramite <em>Record[“nomecampo”]</em>.<br />
Ad esempio se il primo campo di un resultset sarà denominato CHIAVE avremo due modi per accedere al suo valore : tramite l&#8217;indice campo <em>$db->Record[0]</em> oppure tramite il nome campo <em>$db->Record[“CHIAVE”]</em>.<br />
Analizziamo nel dettaglio il nostro metodo :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> next_record<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ibase_fetch_row</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Row</span> <span style="color: #339933;">+=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$stat</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
 <span style="color: #b1b100;">else</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Auto_Free</span><span style="color: #009900;">&#41;</span>
   <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">free_result</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$stat</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
 <span style="color: #666666; font-style: italic;">//Assegnazione valori Array associativo Record[“nomecampo”] = valorecampo</span>
 <span style="color: #000088;">$flds</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Num_Fields</span><span style="color: #339933;">;</span>
 <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$fld</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$flds</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fld</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fld</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
 <span style="color: #666666; font-style: italic;">//ritorno stat: 1=0K, 0=nessun record &amp; effettuato il free se c'è auto_free</span>
 <span style="color: #b1b100;">return</span> <span style="color: #000088;">$stat</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>La proprietà dell&#8217;oggetto Row (che rappresenta il numero di riga corrente) viene incrementata fino a che l&#8217;assegnazione  <em>$this->Record = ibase_fetch_row($this->Query_ID)</em> produce esito positivo.<br />
L&#8217;associazione <em>Record[“nomecampo”]->valore</em>, viene creata partendo dalla proprietà <em>$this->Fields_Info[$fld]["alias"]</em> che è stata valorizzata dal metodo <em>$this->metadata()</em> in exec_query();<br />
Ciclando sul numero di campi del resultset (<em>$this->Num_Fields</em>), aggiunge un elemento all&#8217;array record che ha per chiave il nome del campo e per valore quello relativo all&#8217;indice di questo.<br />
<em>next_record</em> restituirà 1 fino a che non si troverà sull&#8217;ultimo record, momento in cui la variabile <em>$stat</em> (e quindi il valore restituito dal metodo) sarà 0. A questo punto verrà effettuato un check anche sulla nuova proprietà <em>$this->Auto_Free</em>, se questa è valorizzata, allora verrà lanciato il metodo <em>$this->free_result()</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> free_result<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 <span style="color: #990000;">ibase_free_result</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Query_ID</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Questo metodo funziona sulla base della funzione <em>ibase_free_result</em>, che libera la memoria allocata da un resultset.</p>
<p><strong>Mettiamo in pratica</strong></p>
<p>L&#8217;esempio contenuto nel riquadro 2 contiene tutti gli argomenti che abbiamo trattato sin&#8217;ora : Una volta incluso il file “ib_class.inc” contenente il codice della nostra classe si procede con la creazione di una sua istanza nella variabile <em>$db</em>.<br />
La fase successiva prevede la dichiarazione della stringa contenente il codice SQL che vogliamo far eseguire. In questo caso si tratta di voler estrarre dalla tabella PEOPLE tutte le persone che hanno un cognome (PSURNAME) contenente la parola “Corleone” indipendentemente dalle maiuscole o minuscole.<br />
A questo punto viene aggiunto il parametro stringa di confronto e viene eseguita la query.<br />
Da notare come l&#8217;if sia impostato direttamente sull&#8217;esito della query. Se la query non va a buon fine, viene visualizzato il testo dell&#8217;errore mentre in caso di successo viene creata una tabella con i risultati visualizzati.<br />
Prima verranno stampate con un ciclo while le colonne &lt;th&gt; della tabella utilizzando l&#8217;array <em>$db->Fields_Info</em> che è stato creato da <em>$this->metadata</em> in <em>$db->exec_query</em>, infine lo script ciclerà sulla funzione <em>$db->next_record</em> fino a che questa restituirà un valore effettivo (cioè fino a che non arriverà alla fine dell&#8217;elenco) visualizzando il valore di ciascun campo in una cella.<br />
L&#8217;output effettivo di questo script non dovrebbe essere troppo diverso da quello presentato nella figura 1.</p>
<div id="attachment_107" class="wp-caption alignnone" style="width: 188px"><a href="http://www.miamammausalinux.org/wp-content/uploads/2004/10/ib_class_articolo_1-31-figura1.png"><img src="http://www.miamammausalinux.org/wp-content/uploads/2004/10/ib_class_articolo_1-31-figura1.png" alt="Figura 1" title="ib_class_articolo_1-31-figura1" width="178" height="139" class="size-full wp-image-107" /></a><p class="wp-caption-text">Figura 1</p></div>
<p><strong>Conclusioni</strong></p>
<p>Chiaramente l&#8217;implementazione di tutti i metodi dell&#8217;oggetto è puramente indicativa. Ciascuno di essi infatti può essere modificato ed ottimizzato in funzione delle proprie specifiche esigenze. Una personalizzazione mirata è alla base dello sviluppo di un buon progetto.<br />
In questo primo articolo abbiamo realizzato la base per la nostra classe di accesso, nei successivi implementeremo nuovi metodi per renderla più completa possibile : introdurremo metodi specifici per la gestione dei campi Blob, delle transazioni e per tutte le varie tipologie di campi.</p>
<p><strong>Riquadro 1 : Creazione ambiente di test</strong></p>
<p>Prima di iniziare a fare i test con gli script PHP e la nostra classe e&#8217; necessario creare un database di prova, sul quale poter combinare tutti i possibili danni di cui siamo capaci senza nuocere a nessuno&#8230;<br />
Assumiamo come directory di lavoro /home/janet e creiamo un file denominato dbtest.sql con il nostro editor di testo preferito :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">vi</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>janet<span style="color: #000000; font-weight: bold;">/</span>dbtest_create.sql</pre></div></div>

<p>scrivendoci all&#8217;interno i dati per la creazione del nostro db :</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SET</span> SQL DIALECT <span style="color: #cc66cc;">3</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> <span style="color: #ff0000;">'localhost:/home/janet/dbtest.gdb'</span>  USER <span style="color: #ff0000;">'SYSDBA'</span> PASSWORD <span style="color: #ff0000;">'masterkey'</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> PEOPLE <span style="color: #66cc66;">&#40;</span>
    pcode    INTEGER <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    psurname VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">30</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    pname    VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">30</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
    pquote   BLOB SUB_TYPE TEXT SEGMENT SIZE <span style="color: #cc66cc;">240</span><span style="color: #66cc66;">,</span>   
    <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Corleone'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Vito'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'I'</span><span style="color: #ff0000;">'ll make him an offer he can'</span><span style="color: #ff0000;">'t refuse.'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Corleone'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Michael'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Don'</span><span style="color: #ff0000;">'t ask me about my business, Kay.'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Corleone'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Sonny'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Goddamn FBI don'</span><span style="color: #ff0000;">'t respect nothin'</span><span style="color: #ff0000;">'.'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Corleone'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Fredo'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'I'</span><span style="color: #ff0000;">'m smart and I want respect !'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Hagen'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Tom'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Mr. Corleone never asks a second favor once he'</span><span style="color: #ff0000;">'s refused the first, understood ?'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> PEOPLE <span style="color: #66cc66;">&#40;</span>pcode<span style="color: #66cc66;">,</span> psurname<span style="color: #66cc66;">,</span> pname<span style="color: #66cc66;">,</span> pquote<span style="color: #66cc66;">&#41;</span> 
 <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Clemenza'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Peter'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'Mikey, why don'</span><span style="color: #ff0000;">'t you tell that nice girl you love her ?'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
COMMIT;</pre></div></div>

<p>Una volta scritto quanto sopra, salviamo il file e lanciamo questo comando come utente root :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">/</span>opt<span style="color: #000000; font-weight: bold;">/</span>interbase<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>isql <span style="color: #660033;">-i</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>janet<span style="color: #000000; font-weight: bold;">/</span>dbtest_create.sql</pre></div></div>

<p>Se non riceviamo messaggi di errore, dovremmo trovarci nella directory /home/janet il nostro file dbtest.gdb pronto da usare.</p>
<p><strong>Riquadro 2 : il primo script con la nostra classe</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;html&gt;
&lt;body&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> 
 <span style="color: #666666; font-style: italic;">// Inclusione file ib_class </span>
 <span style="color: #b1b100;">include</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ib_class.inc&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #666666; font-style: italic;">// Creazione classe db </span>
 <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ib_class<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;localhost&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;/home/janet/dbtest.gdb&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;SYSDBA&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;masterkey&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #666666; font-style: italic;">// Stringa sql</span>
 <span style="color: #000088;">$ssql</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;SELECT a.PSURNAME, a.PNAME FROM PEOPLE a WHERE upper(a.PSURNAME) LIKE upper(?)&quot;</span><span style="color: #339933;">;</span> 
&nbsp;
 <span style="color: #666666; font-style: italic;">// Aggiungo il parametro</span>
&nbsp;
 <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add_param</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;%Corleone%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;">// Esecuzione query </span>
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">exec_query</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ssql</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #666666; font-style: italic;">// C'e' un errore, lo visualizzo </span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;Si è verificato un errore : &quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Error</span><span style="color: #339933;">;</span> 
 <span style="color: #b1b100;">else</span> 
 <span style="color: #009900;">&#123;</span> 
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;table border=&quot;</span><span style="color: #cc66cc;">1</span><span style="color: #0000ff;">&quot;&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Creo le colonne della tabella</span>
  <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">list</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$colonna</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">=</span><span style="color: #990000;">each</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;th&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Fields_Info</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$colonna</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;alias&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/th&gt;&quot;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
&nbsp;
  <span style="color: #666666; font-style: italic;">// Creo le righe della tabella</span>
  <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">next_record</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> 
  <span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;tr&gt;&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$fld</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Num_Fields</span><span style="color: #339933;">;</span> <span style="color: #000088;">$fld</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;td&gt;&quot;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$db</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Record</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fld</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">&quot;&lt;/td&gt;&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/tr&gt;&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;&lt;/table&gt;&quot;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>  
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p><strong>Allegati</strong></p>
<p>Il file relativo alla classe a questo indirizzo : <a href='http://localhost/miamammausalinux.org/wp-content/uploads/2004/10/ib_class.inc'>ib_class.inc</a>.</p>
<p><strong>La serie comprende questi articoli :</strong></p>
<p>Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/">Parte 1: costruzione della classe e implementazione dei metodi base</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/11/una-classe-php-per-accesso-a-firebird-parte-2/">Parte 2: Gestione dei campi BLOB</a><br />
Una classe PHP per l&#8217;accesso a Firebird &#8211; <a href="http://www.miamammausalinux.org/2004/12/una-classe-php-per-accesso-a-firebird-parte-3/">Parte 3: Gestione delle Transazioni</a></p>
<p><strong>Nota :</strong></p>
<p><em>Questo articolo è originariamente apparso nell&#8217;edizione italiana di Linux Journal nel Ottobre 2004.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miamammausalinux.org/2004/10/una-classe-php-per-accesso-a-firebird-parte-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
