Java & PostgreSQL: da JDBC a Pl/Java (passando per org.postgresql.driver)

Dimensione: px
Iniziare la visualizzazioe della pagina:

Download "Java & PostgreSQL: da JDBC a Pl/Java (passando per org.postgresql.driver)"

Transcript

1 Java & PostgreSQL: da JDBC a Pl/Java (passando per org.postgresql.driver) Ing. Luca Ferrari, PhD fluca1978@gmail.com Italian PostgreSQL Users Group ITPug

2 Synopsis Questa presentazione vuole fungere da punto di riferimento per gli sviluppatori Java che vogliano scrivere applicazioni capaci di gestire i dati contenuti in un cluster PostgreSQL. In questa presentazione verranno mostrate le principali tecniche per la connettività Java verso PostgreSQL (tramite JDBC), il funzionamento interno del driver JDBC ufficiale nonché come estendere il database PostgreSQL con tecnologia Java tramite Pl/Java. Gli esempi di applicazioni/database qui riportati sono a puro scopo didattico. 2 di 182

3 Database didattico CREATE TABLE corso ( corsopk serial NOT NULL, Chiave surrogata della tabella corso. corsoid character varying(10), Chiave reale della tabella corso. descrizione text, Descrizione del corso requisiti text, Elenco dei requisiti richiesti data date, Data in cui si tiene il corso n_ore integer, Numero di ore del corso. materiale oid, Materiale didattico distribuito con il corso ts timestamp with time zone DEFAULT ('now'::text)::timestamp, CONSTRAINT corso_chiave_surrogata PRIMARY KEY (corsopk), CONSTRAINT corso_chiave_reale UNIQUE (corsoid), CONSTRAINT corso_n_ore_check CHECK (n_ore > 0 AND n_ore < 8) ) 3 di 182

4 Database didattico CREATE TABLE partecipante ( partecipantepk serial NOT NULL, Chiave surrogata della tabella nome character varying(20), Nome del partecipante. cognome character varying(20), ts timestamp with time zone DEFAULT ('now'::text)::timestamp, partecipanteid character varying(30), CONSTRAINT partecipante_chiave_surrogata PRIMARY KEY (partecipantepk), CONSTRAINT partecipante_chiave_reale UNIQUE (partecipanteid) ) 4 di 182

5 Database didattico CREATE TABLE j_corso_partecipante ( j_corso_partecipante_pk serial NOT NULL, Chiave surrogata corsopk integer NOT NULL, partecipantepk integer NOT NULL, CONSTRAINT j_corso_partecipante_chiave_surrogata PRIMARY KEY (j_corso_partecipante_pk), CONSTRAINT j_corso_partecipante_corsopk FOREIGN KEY (corsopk) REFERENCES corso (corsopk) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT j_corso_partecipante_partecipantepk FOREIGN KEY (partecipantepk) REFERENCES partecipante (partecipantepk) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) 5 di 182

6 JDBC: applicazioni client 6 di 182

7 JDBC JDBC (Java DataBase Connectivity) è un'api a livello SQL, ossia consente di inglobare comandi SQL nelle proprie applicazioni Java. JDBC fornisce un'unica API CLI per l'accesso a database relazioni eterogenei. L'applicazione non necessita di adattamenti qualora il motore database cambi! Applica il famoso concetto Write Once, Run Everywhere alla connettività database. Si noti che l'idea non è nuovissima: ODBC si propone già come API unificata. Non è indispensabile utilizzare JDBC! 7 di 182

8 Application & Driver APIs JDBC può essere divisa in due parti fondamentali: Application API e Driver API. Le Application API comprendono tutti gli elementi che un'applicazione Java usa per la connessione ad un database. Le Driver API forniscono la base per la scrittura di un driver specifico per un determinato motore relazionale (es. PostgreSQL). Grazie alla suddivisione in due parti, JDBC consente la scrittura di applicazioni portabili e database-independent. All'URL All'URL èèpossibile possibileverificare verificarel'esistenza l'esistenzadidiun undriver driverjdbc JDBC per ogni motore relazionale conosciuto. per ogni motore relazionale conosciuto. 8 di 182

9 Application API vs Driver API Java Application Application ApplicationAPI API Driver DriverAPI API Database Engine 9 di 182

10 Livelli JDBC Le Driver API riconoscono quattro modalità di implementazione differenti, chiamate livelli o type dei driver JDBC: type 1 (JDBC-ODBC bridge): viene sfruttato un accesso ODBC (che deve esistere!). type 2 (Native API Drivers): il driver richiama, tramite JNI, codice nativo (es. C/C++) per la connettività. type 3 (Network Drivers): il driver si collega (via TCP/IP) ad un componente lato server che si interfaccia a sua volta con il database server. type 4 (Pure Java): il driver si collega direttamente al database server e comunica utilizzando un protocollo opportuno. 10 di 182

11 Livelli JDBC: schema riassuntivo JDBC Type 1 ODBC Driver JDBC Type 2 Native Driver Database Engine Java Application JDBC Type 3 Translator (e.g., local JDBC type 2) JDBC Type 4 11 di 182

12 JDBC API 12 di 182

13 Classi principali JDBC Le principali classi/interfaccie della libreria JDBC (java.sql.* e javax.sql.*) sono: DriverManager: rappresenta un repository di istanze di Driver per ogni database server. Ci si rivolge a questa classe per creare una connessione ad uno specifico database (tramite un URL). Driver: rappresenta il componente incaricato di stabilire la connessione con il database server. Può essere caricato all'interno del programma (es. tramite reflection) o specificando la proprietà jdbc.drivers nel momento di invocazione della JVM: java Djdbc.drivers=org.postgresql.Driver myapp 13 di 182

14 Classi principali JDBC (2) Connection: rappresenta una connessione al server database. Tramite di essa è possibile interagire con il database stesso. Statement: implementa una query SQL di qualunque tipo; viene usato per l'esecuzione di un comando sul database server. Si specializza in due sotto-interfaccie: PreparedStatement: una query SQL precompilata e dotata di wrapping dei parametri. CallableStatement: una query SQL che coinvolge una stored procedure. 14 di 182

15 Classi principali JDBC (3) ResultSet: implementazione di un cursore SQL. Contiene un riferimento alla riga dei risultati dall'esecuzione di un comando SQL. Disponde di una serie di metodi per il posizionamento rispetto alle righe e per l'estrazione dei valori di ogni colonna. ResultSetMetaData: informazioni aggiuntive su un ResultSet, quali nomi e numero delle colonne, nome dello schema corrente, etc. DatabaseMetaData: fornisce informazioni aggiuntive sul database stesso, quali versione, stored procedures, foreign keys, etc. SQLException: classe base di ogni eccezione JDBC. 15 di 182

16 Tipica applicazione JDBC Caricamento Caricamentodel del driver necessario driver necessario Istanziazione Driver Connessione Connessionealal database database (Connection) (Connection) Registrazione presso DriverMagaer [while ResultSet.next()] <INVIO> Lettura Letturadel del ResultSet ResultSet Simile all'esecuzione del comando psql -h host -U utente db Simile alla scrittura di una query sulla linea di comando di psql Esecuzione Esecuzionedello dello Statement Statement Creazione Creazionedidiuno uno Statement Statement Chiusra Chiusrarisorse risorseassociate associateaa ResultSet ResultSet ee Statement Statement Chiusura Chiusura connessione connessione (Connection) (Connection) 16 di 182

17 Classi accessorie La libreria fornisce una serie di classi aggiuntive per il mapping fra i tipi SQL e i tipi Java (Types), la gestione di Large Object Data (Clob, Blob), date (Date), timestamp (Timestamp) e array (Array). Come estensioni sono presenti anche le classi per la gestione dei data source (DataSource), dei row set (RowSet) e dei relativi eventi (e.g., RowSetEvent, StatetementEvent). 17 di 182

18 Connessione al database public static void main(string[] args) throws Exception{ try{ // classe del driver String drivername = "org.postgresql.driver"; // url di connessione String databaseurl = "jdbc:postgresql://localhost/pgdaydb"; // caricamento della classe del driver Class driverclass = Class.forName(driverName); // creazione dell'istanza del driver Driver driver = (Driver) driverclass.newinstance(); 18 di 182

19 Connessione al database // // // // a questo punto il driver è registrato presso il DriverManager (il driver di PostgreSQL si registra automaticamente al DriverManager appena la sua classe viene caricata) // essendo il driver caricato e registrato posso // ottenere una connessione al database Connection connection = DriverManager.getConnection(databaseURL, "luca", // username "xxx" // password ); // una volta ottenuta una connessione al database // e' possibile interagire con esso per via di // oggetti di tipo Statement 19 di 182

20 Creazione di uno Statement // creazione di una query e di uno statement // da usare (la query mostra i corsi // che contengono java nella descrizione // e i relativi iscritti) String query = "SELECT c.corsoid, c.descrizione, c.data, c.n_ore, p.nome, p.cognome " + " FROM (corso c LEFT JOIN j_corso_partecipante j ON c.corsopk = j.corsopk) " + " LEFT JOIN partecipante p ON p.partecipantepk = j.partecipantepk " + " WHERE c.descrizione ilike '%java%' "; // notare che lo Statement non e' ancora associato // a nessuna query Statement statement = connection.createstatement(); // effettuo la query ResultSet rs = statement.executequery(query); 20 di 182

21 Analisi dei risultati: ResultSet // visualizzo i dati ottenuti dalla query: l'oggetto // ResultSet (rs) rappresenta un cursore dei risultati // che può essere scorso. while( rs.next() ){ System.out.println("######"); // posso ottenere i dati di una riga chiamando i // metodi getxxx (XXX = tipo di dato) e specificando // il numero della colonna (partendo da 1) o il suo // nome simbolico System.out.println("Id-Corso e descrizione: " + rs.getstring(1) + " " + rs.getstring(2)); System.out.println("Data e numero ore: " + rs.getdate(3) + " " + rs.getint(4)); System.out.println("Iscritto: " + rs.getstring("nome") + " " + rs.getstring("cognome")); } 21 di 182

22 Fine del programma e gestione delle eccezioni // chiusura della connessione connection.close(); } }catch(sqlexception exception){ // eccezione SQL (problema nella query, errore del // server, etc.) }catch(classnotfoundexception ex){ // classe del driver JDBC non trovata }catch(instantiationexception ex){ // errore di reflection (classe driver non // istanziabile) }catch(illegalaccessexception ex){ // errore di reflection (classe driver non // accessibile) } } 22 di 182

23 Esecuzione Riassunto: Caricamento del driver PostgreSQL (necessario solo all'avvio del thread principale dell'applicazione); Creazione di una connessione specificando l'url di connessione; Creazione di uno Statement; Esecuzione dello Statement; Lettura dei risultati tramite il ResultSet; Chiusura delle risorse. 23 di 182

24 Come fa il DriverManager a scegliere il Driver opportuno? Il DriverManager stabilisce quale sia il Driver da utilizzare per una connessione sulla base dell'url di connessione (ogni driver accetta il proprio subprotocol): protocol:subprotocol://hostname/db_name HOSTNAME: specifica l'indirizzo IP/nome dell'host ove è in esecuzione il database. DB_NAME: nome del database cui ci si intende connettere. jdbc:postgres://localhost/pgdaydb protocol: specifica il dominio di appartenenza di questo URL. Indica che l'url si riferisce ad una connessione database (JDBC). subprotocol: specifica il driver che si deve utilizzare. Viene utilizzato da DriverManager per fare il lookup dell'istanza di Driver da restituire per gestire la connessione al database. 24 di 182

25 Considerazioni sul caricamento del driver Il caricamento e l'istanziazione del driver JDBC può avvenire attraverso reflection o direttamente: // reflection Class driverclass = Class.forName( org.postgresql.driver ); Driver driverinstance = driverclass.newinstance(); // istanziazione diretta Driver driverinstance = new org.postgresql.driver(); I driver hanno sempre un costruttore di default senza argomenti, I driver hanno sempre un costruttore di default senza argomenti, e quindi sono sempre istanziabili mediante reflection. e quindi sono sempre istanziabili mediante reflection. 25 di 182

26 Considerazioni sul ResultSet Un ResultSet rappresenta un cursore sui risultati di una query. Il posizionamento fra le righe del cursore avviene tramite metodi specifici, quali next() e previous(). Ogni ResultSet è legato allo Statement che lo ha generato; se lo Statement viene alterato il ResultSet è automaticamente invalidato! Esistono metodi per recuperare il valore di ogni colonna secondo il tipo di appartenenza (String, int, Date,...): <tipo_java> get<tipo_java>(int colonna) <tipo_java>get<tipo_java>(string nomecolonna) Ogni tipo SQL viene mappato in un tipo Java (e viceversa) mediante una specifica tabella di conversione ( html). Tale tabella può essere estesa dall'utente per mappare i tipi user defined. SiSipresti prestiattenzione attenzionealalfatto fattoche, che,contrariamente contrariamentealla allalogica logica degli array, le colonne sono numerate partendo da 1! degli array, le colonne sono numerate partendo da 1! 26 di 182

27 ResultSet: errori frequenti Si richiama getxxx(..) con un indice di colonna errato (maggiore) rispetto al numero di colonne estratte dalla query. Si richiama getxxx(..) prima di aver chiamato almeno una volta next(). 27 di 182

28 Esecuzione di un INSERT/UPDATE/DELETE // creazione di una query e di uno statement // da usare per inserire un nuovo corso String query = "INSERT INTO corso(corsoid,descrizione) VALUES('Java_adv', 'Corso avanzato su Java/JDBC') "; Statement statement = connection.createstatement(); // chiedo al server di eseguire la query e // di fornirmi il numero di righe "toccate" // tutte le query che modificano i dati vanno eseguite // attraverso il metodo executeupdate(..) int rows = statement.executeupdate(query); if( rows > 0) System.out.println("Inserimento effettuato con successo:" + rows + " righe inserite"); // chiusura della connessione connection.close(); 28 di 182

29 Esecuzione Riassunto: Caricamento del driver PostgreSQL (necessario solo all'avvio del thread principale dell'applicazione); Creazione di una connessione specificando l'url di connessione; Creazione di uno Statement; Esecuzione dello Statement; Lettura del valore di ritorno dell'esecuzione dello Statement, tale valore indica il numero di righe toccate dalla query; Chiusura delle risorse. 29 di 182

30 Compilazione del driver 30 di 182

31 Driver JDBC per PostgreSQL PostgreSQL fornisce un driver JDBC conforme ai livelli 2,3 e 4. Il sito web del progetto è dal quale è possibile scaricare il driver (in formato binario o sorgente), navigare la documentazione Javadoc della parte public delle API. E' presente una mailing list specifica: pgsql jdbc@postgresql.org; gli attuali mantainer del Driver sono Dave Cramer, Kris Jurka, Oliver Jowett. 31 di 182

32 Decompressione dei sorgenti I sorgenti vengono rilasciati sotto forma di archivio compresso (tarball): postgresql jdbc src.tgz E' possibile decomprire programma tar: i sorgenti usando il tar xzvf postgresql jdbc src.tgz ottenendo una directory che contiene l'albero dei sorgenti ls l postgresql jdbc rw r r 1 luca luca :02 build.properties rw r r 1 luca luca :00 build.xml drwxr xr x 2 luca luca :22 doc rw r r 1 luca luca :25 LICENSE drwxr xr x 3 luca luca :22 org rw r r 1 luca luca :24 README rwxr xr x 1 luca luca :15 update translations.sh 32 di 182

33 Compilazione: requisiti Per compilare il driver JDBC è necessario utilizzare Apache Ant ( uno strumento di compilazione automatico per Java. Ant è uno strumento concettualmente simile a make, ma ottimizzato per la gestione dei progetti Java. Esso stesso è scritto in Java, e questo ne facilita la fruibilità nello sviluppo di componenti Java. Ant necessita della presenza di un file di build (solitamente build.xml) che contiene i task del processo di compilazione. E' possibile specificare proprietà di compilazione mediante file di proprietà Java (file properties). 33 di 182

34 Compilazione: build Il file di build del driver è build.xml, e può essere omesso nell'invocazione di ant: [luca@fluca:/sviluppo/java/contrib src/postgresql jdbc src]$ ant Buildfile: build.xml all: prepare: check_versions: check_driver: driver: compile: [javac] Compiling 144 source files to /sviluppo/java/contrib src/postgresql jdbc src/build [javac] Note: Some input files use or override a deprecated API. [javac] Note: Recompile with Xlint:deprecation for details. [javac] Note: Some input files use unchecked or unsafe operations. [javac] Note: Recompile with Xlint:unchecked for details. jar: [jar] Building jar: /sviluppo/java/contrib src/postgresql jdbc src/jars/postgresql.jar BUILD SUCCESSFUL Total time: 5 seconds [luca@fluca:/sviluppo/java/contrib src/postgresql jdbc src]$ 34 di 182

35 Compilazione: risultato Al termine del processo di compilazione viene generato un file postgresql.jar nella sottodirectory jars: src/postgresql jdbc src]$ ls l jars/ total 436 rw r r 1 luca luca :22 postgresql.jar [luca@fluca:/sviluppo/java/contrib src/postgresql jdbc src]$ Il file jar prodotto deve essere incluso nel classpath corrente affinché i programmi Java possano caricare il driver. $ export CLASSPATH=`pwd`/jars/postgresql.jar:$CLASSPATH $ echo $CLASSPATH /sviluppo/java/contrib src/postgresql jdbc src/jars/postgresql.jar: $ 35 di 182

36 Compilazione: risultato (2) Un altro file importante viene generato: Driver.java $ ls l org/postgresql/driver.java* rw r r 1 luca luca :21 org/postgresql/driver.java rw r r 1 luca luca :18 org/postgresql/driver.java.in $ Prima della compilazione infatti il solo file Driver.java.in è presente. Il file Driver.java viene generato dinamicamente durante il processo di build, a seconda del livello JDBC del driver. 36 di 182

37 Compilazione in Eclipse Definire un nuovo progetto basato su un file Ant esistente. (1) (2) Selezionare il file di build dalla directory dei sorgenti; specificare le proprietà del progetto. 37 di 182

38 Compilazione in Eclipse (2) (3) Ricercare il file build.xml tramite il modulo Ant di Eclipse. 38 di 182

39 Compilazione in Eclipse (3) (4) Eseguendo il file di build il progetto viene compilato. 39 di 182

40 JDBC 2, 3 o 4? Il driver JDBC di Postgresql supporta solo i livelli JDBC 2,3 e 4. L'albero dei sorgenti include i package per ogni versione JDBC. $ ls org/postgresql/ l... drwxr xr x 3 luca luca :23 jdbc2 drwxr xr x 2 luca luca :23 jdbc3 drwxr xr x 2 luca luca :23 jdbc4... $ La decisione su quale livello di driver (org.postgresql.driver) viene presa durante il processo di build in base alla versione della JVM. In particolare la versione viene stabilita sulla base della Java Virtual Machine installata sul sistema. 40 di 182

41 Driver.java.in Il file org.postgresql.driver.java.in è un file che viene tramutato nel driver Java vero e proprio durante il processo di build Ant. Al suo interno il file Driver.java.in contiene dei segnaposti per le classi JDBC del livello opportuno. 41 di 182

42 Scelta del livello JDBC Il file contiene build.xml un target, check_versions, che controlla quale versione di JVM sia disponibile e, di conseguenza, quale versione di driver sia la più appropriata. A seconda del livello stabilito viene impostata a true la proprietà jdbcx. 42 di 182

43 Scrittura del livello JDBC Il target driver si occupa della scrittura del file Driver sostituendo i marcaposto al suo interno con le classi del livello JDBC scelto. Si noti che viene utilizzata la funzionalità di filtro (filter) di Ant per la sostituzione dei marcaposto (token) con le classi concrete. Diverse altre classi sono specificate con lo stesso procedimento. 43 di 182

44 Scrittura del livello JDBC (2) Viene fatto un controllo sulla proprietà jdbcx, impostata precedentemente dal target check_versions. (1) 44 di 182

45 Scrittura del livello JDBC (3) (2) Vengono impostati i token marcaposto da sostituire nel file Driver.java.in; ogni token specificato in build.xml trova corrispondenza in Driver.java.in 45 di 182

46 Scrittura del livello JDBC (4) (3) Il file Driver.java.in viene copiato in Driver.java applicando le condizioni di filtro. 46 di 182

47 JDBC: tipi di Statement 47 di 182

48 PreparedStatement Un PreparedStatement è un oggetto che memorizza uno statement SQL precompilato, che può essere parametrizzato e che può eseguire più efficientemente di uno Statement normale. L'idea è di precompilare un comando SQL parziale e di completarlo successivamente, al momento in cui l'esecuzione sia necessaria. Lo statement precompilato può poi essere riutilizzato più volte, cambiando eventualmente i parametri di esecuzione. Un PreparedStatement è una sottointerfaccia di Statement! Essendo Essendouno unostatement statementparametrizzabile, parametrizzabile,preparedstatement PreparedStatementfornisce forniscedei deimetodi metodi setxxx setxxxeegetxxx getxxxper perimpostare impostarei iparametri parametrididiesecuzione. esecuzione. 48 di 182

49 Prepared Statement // creazione di una query di inserimento e dello // statement precompilato per la sua esecuzione String query = "INSERT INTO corso(corsoid,descrizione) VALUES(?,?) "; PreparedStatement statement = connection.preparestatement(query); // inserisco alcuni corsi fornendo gli opportuni // parametri al server int rows = 0; for(int i = 0; i < 10; i++){ String corsoid = "corso_" + i; String descrizione = "Nessuna descrizione "; // impostazione dei parametri nello statement statement.setstring(1, corsoid); statement.setstring(2, descrizione); // eseguo lo statement (non devo specificare una query // poiché lo statement è già stato precompilato) rows += statement.executeupdate(); } 49 di 182

50 Considerazioni: PreparedStatement Un PreparedStatement utilizza una sintassi speciale per le query SQL: ogni carattere? viene usato come un marcatore per un parametro che verrà specificato in seguito. In maniera duale ad un ResultSet vengono forniti dei metodi setxxx(numpar, value). Il vantaggio dei PreparedStatement è che possono essere memorizzati e precompilati dal database server, aumentado le prestazioni nel caso di cicli (l'ottimizzatore potrebbe però stabilire piani diversi a seconda della selettività dei parametri). Si Sipresti prestiattenzione attenzionealalfatto fattoche che i iparametri parametrisono sononumerati numeratipartendo partendoda da1!1! 50 di 182

51 Statement vs PreparedStatement Statement: PreparedStatement: query statiche o poco variabili; query parametriche; nessuna necessità escaping dei parametri. query base da eseguire ciclicamente a seconda di parametri run-time; di escaping di parametri usati nella query stessa. L'utilizzo di PreparedStatement è preferibile in molte situazioni! 51 di 182

52 CallableStatement L'interfaccia CallableStatement viene usata in maniera analoga ai PreparedStatement per l'invocazione di una Stored Procedure. La sintassi utilizzata per l'invocazione è la seguente: { call stored_procedure(?,?,...) } Viene specificato il nome della stored procedure da invocare, seguito dalla lista di eventuali parametri. La funzione viene invocata con il metodo executequery() che restituisce un ResultSet. 52 di 182

53 JDBC: Utilizzo avanzato 53 di 182

54 Esecuzione di comandi arbitrari Si supponga di voler creare una vista definita come segue: CREATE VIEW vw_partecipanti AS SELECT c.corsoid, c.descrizione, c.data, p.cognome, p.nome FROM partecipante p JOIN corso c ON c.corsopk = p.corsopk ORDER BY c.corsoid, p.cognome, p.nome Come si può notare l'esecuzione della query non produce alcun risultato (in termine di numero di righe modificate) pur alterando la struttura del database. 54 di 182

55 Esecuzione di comandi arbitrari // creazione di uno statement Statement statement = connection.createstatement(); // preparazione della query String sql = "CREATE VIEW vw_partecipanti AS SELECT c.corsoid, c.descrizione, c.data, p.cognome, p.nome FROM partecipante p JOIN corso c ON c.corsopk = p.corsopk ORDER BY c.corsoid, p.cognome, p.nome"; int result = statement.executeupdate(sql); System.out.println("Risultato di esecuzione: " + result); 55 di 182

56 JDBC: creazione della procedura // creazione di uno statement Statement statement = connection.createstatement(); // preparazione della funzione StringBuffer buffer = new StringBuffer(1000); buffer.append( "CREATE OR REPLACE FUNCTION... ); buffer.append(" RETURNS void AS $BODY$ DECLARE... ); // chiamata della stored procedure int result = statement.executeupdate(buffer.tostring()); System.out.println("Risultato della creazione della procedura: " + result); 56 di 182

57 JDBC: invocazione della procedura // invocazione della funzione String sql = "{ call f_nuovo_corso(?,?,?) }"; // preparazione della chiamata e impostazione dei parametri CallableStatement cstatement = connection.preparecall(sql); cstatement.setint(1, 2); cstatement.setstring(2, "Corso2009"); Calendar calendar = Calendar.getInstance(); calendar.set(calendar.day_of_month, 7); calendar.set(calendar.month, 7); calendar.set(calendar.year, 2009); cstatement.setdate(3, new java.sql.date(calendar.gettimeinmillis()) ); // invocazione della funzione ResultSet resultset = cstatement.executequery(); // in questo caso non ho risultati di 182

58 CallableStatement L'interfaccia CallableStatement viene usata in maniera analoga ai PreparedStatement per l'invocazione di una Stored Procedure. La sintassi utilizzata per l'invocazione è la seguente: { call stored_procedure(?,?,...) } {?= stored_procedure(?,?,...) } Viene specificato il nome della stored procedure da invocare, seguito dalla lista di eventuali parametri. L'invocazione avviene tramite il metodo executequery() che restituisce un ResultSet. E' possibile registrare parametri di input/output e ottenerne il valore direttamente dallo statement. 58 di 182

59 Batch L'interfaccia Statement consente l'esecuzione batch di una serie di comandi SQL: public void addbatch(string sql) mediante tale metodo è possibile assegnare una serie di istruzioni SQL da eseguire sequenzialmente in un momento successivo. L'esecuzione del gruppo di comandi avviene mediante il metodo executebatch(), che restituisce i singoli valori di ritorno dell'esecuzione di ogni comando. public int[] executebatch() 59 di 182

60 Batch: un primo esempio // creo uno statement Statement statement = connetion.createstatement(); // imposto i comandi da eseguire nel batch String sql = INSERT INTO... ; // aggiungo questa istruzione al batch statement.addbatch(sql); // nuova istruzione da aggiungere al batch sql = INSERT INTO... ; statement.addbatch(sql);... // eseguo il batch int result[] = statement.executebatch(); // controllo i risultati di ogni comando for(int i=0; i<result.length; i++) System.out.println( Comando +(i+1)+ risultato + result[i]); 60 di 182

61 Batch & PreparedStatement L'utilizzo dei batch agevola i casi in cui siano presenti cicli. E' possibile utilizzare oggetti PreparedStatement al fine di unire i vantaggi di un'esecuzione batch e della parametrizzazione dei comandi SQL. // query parametri String sql = UPDATE corso SET descrizione=? WHERE corsoid=? ; PreparedStatement statement = connection.preparestatement(sql); for(int i=0; i< 10; i++){ statement.setstring(1, descrizione[i]); statement.setstring(2, id[i]); statement.addbatch(); } // esecuzione int result[] = statement.executebacth(); 61 di 182

62 Batch: considerazioni Solitamente l'utilizzo di un batch risulta più efficiente che l'esecuzione delle singole operazioni in modo separato (ottimizzazione da parte del driver). Si presti attenzione al fatto che un batch è differente da una transazione, tuttavia può essere usato per rendere più compatto (e quindi leggibile) il codice di una transazione. 62 di 182

63 Scrollable ResultSet Uno scrollable ResultSet è un tipo particolare ResultSet che offre una funzionalità di scrolling. di E' possibile muoversi attraverso le righe in avanti e indietro, saltare righe, posizionarsi in modo relativo o assoluto, etc. Il tipo di scrolling deve essere specificato a livello di creazione dello Statement, specificando il tipo di scrolling (e di aggiornabilità) come parametri del metodo createstatement(..), in modo da consentire al database di gestire le risorse. IlIldriver driverpostgresql PostgreSQLutilizza utilizzainternamente internamenteun unvector Vectorper per contenere contenereleletuple tupledel delresultset; ResultSet;mediante medianteun unindice indice riesce a garantire lo scrolling di tali tuple. riesce a garantire lo scrolling di tali tuple. 63 di 182

64 Tipo di scrolling Il tipo di un ResultSet può essere specificato tramite tre valori predefiniti: ResultSet.TYPE_FORWARD_ONLY (1003) è il classico ResultSet che può essere consultato solo in avanti. ResultSet.TYPE_SCROLL_INSENSITIVE (1004) può essere consultato in entrambe le direzioni ma non riflette cambiamenti fatti al database mentre è aperto. ResultSet.TYPE_SCROLL_SENSITIVE (1005) può essere consultato in entrambe le direzioni e riflette ogni cambiamento apportato. Il tipo di scrolling può essere ricavato a tempo di esecuzione tramite il metodo int ResultSet.getType(); 64 di 182

65 Posizionamento all'interno del ResultSet L'interfaccia ResultSet mette a disposizione diversi metodi di posizionamento: beforefirst(), afertlast() restituiscono true se si ci si trova oltre la prima o l'ultima riga. next(), previous() muovono di una riga in avanti o indietro il cursore. absolute(int), relative(int) spostano il cursore alla riga specificata in modo assoluto o relativo (dalla posizione corrente). Un indice negativo considera lo spostamento all'indietro (es. -1 sposta all'ultima riga nel caso di posizionamento assoluto o alla riga precedente nel caso di posizionamento relativo). getrow() ritorna il numero di riga (valore assoluto) a cui si è posizionati correntemente. 65 di 182

66 Esempio di scrollable ResultSet // ottengo il result set di una query ResultSet rs = statement.executequery(); while( rs.next() ){ // esecuzione in avanti (solo righe pari) int numero_riga = rs.getrow(); if( (numero_riga % 2) == 0 ){ System.out.println("######"); System.out.println("Id-Corso e descrizione: " + rs.getstring(1) + " " + rs.getstring(2)); } } // torno indietro e processo solo le righe dispari while( rs.previous() ){ int numero_riga = rs.getrow(); } if( (numero_riga % 2)!= 0 ){...} 66 di 182

67 ResultSet aggiornabili JDBC v2 permette di aggiornare (inserire, modificare, cancellare) le righe di una query usando direttamente il ResultSet corrispondente. In sostanza non si è obbligati a creare un comando di update/insert ma si può modificare il valore di una colonna direttamente operando sui risultati di una query. E' un tentativo di nascondere i dettagli SQL e di rendere il sistema più Object-Oriented. 67 di 182

68 ResultSet aggiornabili (2) Per rendere tutto ciò possibile l'interfaccia ResultSet include una serie di metodi simili a quelli per la definizione dei parametri di un PreparedStatement. Ad esempio: updatestring(int column, String value); updateint(int column, int value);... Esistono poi dei metodi speciali per aggiornare/inserire/cancellare e aggiornare i valori della riga corrente: updaterow(); insertrow(); deleterow(); refresh(); 68 di 182

69 Tipo di aggiornabilità Il tipo di un ResultSet, relativamente alla sua aggiornabilità, può essere specificato tramite due valori predefiniti: ResultSet.CONCUR_READ_ONLY (1007) è ResultSet che non può essere aggiornato. il classico ResultSet.CONCUR_UPDATABLE (1008) può essere aggiornato e quindi supporta inserimento, modifica e cancellazione di righe. Il tipo di aggiornabilità può essere ricavato a tempo di esecuzione tramite il metodo int ResultSet.getType(); 69 di 182

70 Inserimento di una riga L'inserimento di una riga in un ResultSet è un'operazione leggermente più complessa rispetto all'aggiornamento. Occorre infatti istruire il ResultSet affinché prepari posto per i valori della riga che si vuole inserire, assegnare tali valori e confermare (salvare) l'inserimento della nuova riga. Se il ResultSet è di tipo scroll sensitive la riga inserita sarà visibile senza bisogno di aggiornamenti del ResultSet stesso. 70 di 182

71 Inserimento di una riga: un approccio visuale La procedura di inserimento di una nuova riga è simile alla procedura usata in molti programmi visuali di accesso e modifica dei database: (1) viene ottenuto il ResultSet relativo ad una specifica query; (2) si passa oltre l'ultima riga, usando una riga vuota come spazio temporaneo per l'inserimento dei valori. Si usa il metodo movetoinsertrow(); (3) vengono salvati i valori inseriti. Si usa il metodo insertrow(). 71 di 182

72 Inserimento di una riga in un ResultSet // processo il result set ed inserisco una nuova riga (max 4) // ad ogni riga pari (non significa DOPO ogni riga pari!) while (rs!= null && rs.next()) { int numero_riga = rs.getrow(); if( ((numero_riga % 2) == 0) && inserite < 4 ){ // inserisco una nuova riga in fondo al result set rs.movetoinsertrow(); rs.updatestring(1, "CorsoRS" + numero_riga); rs.updatestring(2, "Prova di inserimento da ResultSet"); rs.insertrow(); // torno alla riga cui ero prima dell'inserimento rs.movetocurrentrow(); inserite++; } String corsoid = rs.getstring(1); String descrizione = rs.getstring(2); System.out.println("Riga numero " + numero_riga + " " + corsoid + " = " + descrizione); } 72 di 182

73 JDBC: Transazioni 73 di 182

74 JDBC e transazioni Il driver JDBC lavora in modalità auto-commit: ogni istruzione eseguita tramite uno Statement viene automaticamente confermata. E' come se si eseguissero transazioni monocomando. Per prendere il controllo sulla transazione e segnarne l'inizio e la fine (BEGIN-END) è necessario disabilitare l'auto-commit del driver e forzare un esplicito commit/rollback. 74 di 182

75 Schema di funzionamento // disabilito auto commit connection.setautocommit(false); // effettuo del lavoro, INSERT, UPDATE, ecc. e tengo // traccia se devo fare un rollback... rollback = true; // tutto fatto if(! rollback ) connection.commit(); else connection.rollback(); connection.setautocommit(true); // ripristino auto-commit 75 di 182

76 Transazioni: livello di isolamento E' possibile impostare il livello di isolamento di una transazione. I livelli di isolamento sono memorizzati come costanti (interi) nell'oggetto Connection e possono valere: Connection.TRANSACTION_READ_COMMITTED impedisce che ci siano dirty-reads, ma consente unrepeatable e phantom reads; Connection.TRANSACTION_READ_UNCOMMITTED non consente nessun tipo di dirty, unrepeatable e phantom reads; Connection.TRANSACTION_REPEATABLE_READ consente solo phantom reads; Connection.TRANSACTION_SERIALIZABLE sono serializzabili. le transazioni 76 di 182

77 Transazioni: riassunto & considerazioni L'inizio di una transazione deve essere eplicitato a livello di connessione (Connection) disabilitando la modalità di auto-commit. Tutte le operazioni eseguite tramite uno Statement dopo aver disabilitato l'auto-commit fanno parte della transazione. La fine di una transazione deve forzare un esplicito commit o rollback sulla connessione. Una volta terminata la transazione è necessario riabilitare l'auto-commit, altrimenti le istruzioni succesive faranno parte di una nuova transazione (il driver non ri-abilita da solo l'auto-commit!). 77 di 182

78 JDBC: DataSource 78 di 182

79 DataSource Le API JDBC 2 introducono nel package javax.sql l'interfaccia DataSource che si comporta come un wrapper attorno alla connettività di un un database. In sostanza un DataSource è un'oggetto che contiene tutte le informazioni che servono per la connettività verso la sorgente dati (database) quali URL, username, password, auto-commit mode, etc. Lo scopo dei DataSource è quello di disaccoppiare l'impostazione dei parametri di connettività (tipicamente amministrativi) dal loro utilizzo (tipicamente applicativo). Diverse applicazioni possono condividere la stessa DataSource (ad esempio tramite JNDI); una modifica nel DataSource (ad esempio modifica all'url) non necessita nessun intervento sulle applicazioni che lo utilizzano. 79 di 182

80 ConnectionPoolDataSource Un tipo particolare di sorgente dati è il ConnectionPoolDataSource che consente di gestire le connessioni in pool. L'idea è quella di mantenere le connessioni al database in una cache, in modo da renderle disponibili a diversi componenti man mano che vengono richieste. Non venendo aperte/chiuse di continuo, le connessioni vengono erogate con tempi di risposta più bassi rispetto all'approccio classico. L'utilizzo delle sorgenti dati con pool richiede però qualche passaggio in più rispetto all'uso delle sorgenti dati semplici. Viene comunque garantito il disaccoppiamento fra la parte amministrativa e quella applicativa. 80 di 182

81 DataSource & PostgreSQL I driver JDBC di PostgreSQL mettono a disposizione due tipi principali di DataSource (contenute nel package org.postgresql.ds): PGSimpleDataSource un DataSource senza alcun tipo di pooling. Implementa javax.sql.datasource e dispone di un metodo getconnection() che fornisce la connessione al database. Ad esempio: DataSource datasource = new PGSimpleDataSource();... Connection connection = datasource.getconnection(); 81 di 182

82 DataSource & PostgreSQL PGPoolingDataSource un DataSource con capacità di pooling delle connessioni. Implementa javax.sql.connectionpooldatasource e mette a disposizione un metodo getpooledconnection() che fornisce un oggetto javax.sql.pooledconnection, al quale si può richiedere la connessione tramite getconnection(). Ad esempio: ConnectionPoolDataSource datasource = new PGConnectionPoolDataSource();... PooledConnection pooledconnection = datasource.getpooledconnection(); Connection connection = pooledconnection.getconnection(); 82 di 182

83 Impostazione delle proprietà di una sorgente dati Le proprietà delle sorgenti dati vengono impostati tramite metodi set (e lette dai relativi metodi get secondo le specifiche Java Beans). Solitamente gli ambienti server mettono a disposizione dei file di configurazione (es. XML) che consentono di specificare le varie proprietà. L'ambiente container (es. Tomcat) si farà poi carico di leggere tale file di configurazione e di impostare le proprietà di connessione nella sorgente dati. servername Indirizzo IP o nome del server database databasename Nome del database cui collegarsi portnumber Porta a cui collegarsi tramite TCP/IP user Utente da usare per la connessione password Password per l'utente di cui sopra initialconnections Numero di connessioni da creare all'avvio maxconnections Massimo numero di connessioni istanziabili 83 di 182

84 Esempio di uso di DataSource // creazione di un data source per PostgreSQL PGConnectionPoolDataSource datasource = new org.postgresql.ds.pgconnectionpooldatasource(); // impostazione dei parametri di connessione datasource.setdatabasename("pgdaydb"); datasource.setuser("luca"); datasource.setpassword(null); datasource.setservername("localhost"); datasource.setdefaultautocommit(true); // ora il datasource andrebbe esportato e reso disponibile // ad altre applicazioni, ad esempio tramite JNDI... // prelevo la sorgenti dati ConnectionPoolDataSource source = (ConnectionPoolDataSource) datasource; // oppure // PooledConnection pooledconnection = // source.getpooledconnection(); 84 di 182

85 Spring La libreria Spring fornisce un sottoinsieme di classi di utilità per la connessione a database e la realizzazione di DAO. <! il template jdbc che deve essere inizializzato con una datasource > <bean id="jdbctemplate" class="org.springframework.jdbc.core.jdbctemplate"> <constructor arg> <ref bean="datasource" /> </constructor arg> </bean> <! inmpostazione della datasource > <bean id="datasource" class="org.springframework.jdbc.datasource.drivermanagerdatasource"> <property name="driverclassname" value="org.postgresql.driver" /> <property name="url" value="jdbc:postgresql:// /hrpmdb" /> <property name="username" value="hrpm" /> <property name="password" value="hrpm" /> </bean> 85 di 182

86 Spring lato applicativo Lato applicativo occorre ottenere il jdbctemplate e usare uno dei suoi metodi per effettuare le query. // insert the address in the database this.jdbctemplate.update( this.getinsertquery(), toinsert.getprimarykey(), toinsert.getstreet(), toinsert.getcity(), toinsert.getcountry(), toinsert.getstate(), toinsert.getphone(), toinsert.getzipcode(), toinsert.getfax() ); 86 di 182

87 Java Transaction API 87 di 182

88 Java Transaction API (JTA) La Java Transaction API (JTA) è un insieme di interfaccie e classi che forniscono una astrazione verso un sistema di transazioni distribuite. Una transazione distribuita è una transazione che coinvolge più risorse (database) allo stesso momento. La necessità di mantenere coerenti le risorse (database) richiede protocolli appositi per la decisione di commit/rollback globale. La JTA si appoggia su una implementazione specifica del server, chiamata Java Transaction Service (JTS). Il JTS è responsabile di implementare il Transaction Manager, che è il componente che prende la decisione globale sul commit/rollback. 88 di 182

89 Transazioni distribuite in Java Java Application User UserTransaction Transaction Interface Interface Transaction TransactionManager Manager JDBC JDBCDriver Driver Application Server Database Engine Database Engine 89 di 182

90 Transazioni distribuite in Java L'interfaccia javax.transaction.usertransaction consente di definire i confini di una transazione distribuita, ossia quale sezione di codice debba essere eseguito come transazione. La sua implementazione dipende dal container che si sta utilizzando. L'interfaccia javax.transaction.transactionmanager consente la gestione delle risorse di transazione al container. L'interfaccia javax.transaction.xa.xaresource rappresenta una risorsa XA da gestire. 90 di 182

91 Transazioni distribuite: Commit a due fasi Il protocollo di commit a due fasi (Two Phase Commit) è un algoritmo distribuito che consente a tutti i nodi che partecipano alla transazione di accordarsi all'unisono per un commit o un rollback. (fase 1: pre-commit) Il coordinatore invia un query-to-commit a tutti i partecipanti. Ogni partecipante effettua le operazioni, aggiorna i propri log (undo e redo) e invia un messaggio di commit o rollback al coordinatore. (fase 2: commit) Quando il coordinatore ha tutti i messaggi dei partecipanti prende la decisione: se tutti hanno inviato un commit il coordinatore conferma il commit ai partecipanti che rendono permanenti le modifiche e inviano un acknowledgement. Il coordinatore chiude la transazione quando riceve tutti gli acknoweldgement. se almeno un partecipante ha inviato un rollback il coordinatore invia un rollback ai partecipanti, che annullano la loro transazione locale e confermano il rollback al coordinatore. 91 di 182

92 Risorse X/Open CAE X/Open CAE specifica gli oggetti e le interfaccie da usare nelle transazioni distribuite (Distributed Transaction Processing: the XA specification): definisce cosa un gestore di risorse debba fare per supportare le transazioni distribuite. Il supporto XA del driver è fondamentale per consentire l'uso con transazioni distribuite. Il driver JDBC di PostgreSQL supporta XA dalla versione 8.1, anche se senza supporto per il transaction interleaving (capacità di usare la stessa connessione per differenti transazioni contemporanee). 92 di 182

93 JTA & Driver JDBC Nonostante il Transaction Manager sia il componente più importante, il driver JDBC deve fornire supporto a XADatasource, XAConnection e XAResource. Le classi di più alto livello JTA, quali ad esempio UserTransaction e TransactionManager non sono nello scope di un driver JDBC quanto di un application server. 93 di 182

94 Identificazione di una transazione Una transazione è identificata da un Transaction ID composto da tre parti fondamentali: format ID: specifica il naming schema delle transazioni (es. OSI CCR Commitment, Concurrency e Recovery). branch qualifier: un branch rappresenta una singola richiesta ad un resource manager. global transaction id: un identificativo globale della transazione in tutto il sistema. L'implementazione di un transaction dipende dal container/sistema utilizzato. id (javax.transaction.xa.xid) 94 di 182

95 Creazione di uno Xid public class PgDayXid implements Xid{ // Il formatid specifica quale specifica si sta usando. // Se vale 0 allora si sta usando la specifica OSI CCR // (OSI Commitment, Concurrency and Recovery). // Se vale 1 allora l'xid non è valido, // mentre se è superiore a zero allora indica // una specifica proprietaria. protected int formatid = 0; // identificativo globale della transazione corrente. (0 64 bytes) protected byte[] globaltransactionid = null; // identificativo del ramo della transazione corrente. (0 64 bytes) protected byte[] branchqualifier = null; public byte[] getbranchqualifier() { return this.branchqualifier; } public int getformatid() { return this.formatid; } public byte[] getglobaltransactionid() { return this.globaltransactionid; } 95 di 182

96 Creazione di uno Xid public void setglobaltransactionid(byte[] gtid){ // tengo conto solo dei primi 64 bytes... if( gtid!= null && gtid.length > 64 ){ System.arraycopy( gtid, 0, this.globaltransactionid, 0, 64 ); } else this.globaltransactionid = gtid; } public void setbranchqualifier(byte[] bq){... } public void setformatid(int id){... } } 96 di 182

97 Utilizzo di JTA public static void main(string[] args) throws Exception { // 1) creazione di un datasource agganciato al database PGXADataSource datasource = new PGXADataSource(); datasource.setdatabasename("pgday"); // nome del database datasource.setuser("luca"); // username datasource.setpassword("fluca"); // password dell'utente datasource.setservername("localhost"); // indirizzo di connessione // del database // 2) ottengo una connessione al database System.out.println("Tentativo di connessione al database..."); XAConnection connection = datasource.getxaconnection(); System.out.println("Connesso!"); // 3) ottengo una risorsa per proteggere la transazione XAResource resource = connection.getxaresource(); 97 di 182

98 Utilizzo di JTA // 4) devo avere un id della transazione che sto per usare PgDayXid identifier = new PgDayXid(); identifier.setbranchqualifier( new byte[] {0x01, 0x02, 0x03, 0x04, 0x05}); identifier.setglobaltransactionid( new byte[] {0x05, 0x04, 0x03, 0x02, 0x01}); identifier.setformatid(100); // 5) eseguo la transazione try{ // 6) inizio della transazione resource.start(identifier, XAResource.TMNOFLAGS); // 7) esecuzione di operazioni JDBC Connection jdbcconnection = connection.getconnection(); jdbcconnection.setautocommit(false); // bug del driver! Statement statement = jdbcconnection.createstatement(); String sql = "INSERT INTO corso(corsoid, descrizione) VALUES('XA1', 'Corso su JTA')"; int inserted = statement.executeupdate(sql); System.out.println("Sono state inserite " + inserted + " righe"); 98 di 182

99 Utilizzo di JTA // 8) ho terminato la transazione resource.end(identifier, XAResource.TMSUCCESS); // 9) controllo se il transaction manager consente il commit // (fase di precommit) int commit = resource.prepare(identifier); System.out.println("Valore del prepare " + commit); if( commit == XAResource.XA_OK ) // commit definitivo resource.commit(identifier, // identificativo transazione false); // false = commit 2 fasi else resource.rollback(identifier); }catch(xaexception e){ e.printstacktrace(); } } 99 di 182

100 Sospensione di una transazione E' possibile sospendere una transazione distribuita per dare modo al processo corrente di eseguire operazioni locali. E' necessario terminare la transazione distribuita e avviarla nuovamente specificando come flag rispettivamente TMSUSPEND e TMRESUME. // 8) sospensione della transazione distribuita resource.end(identifier, XAResource.TMSUSPEND); // 8 bis) effettuo degli statement fuori dalla transazione // distribuita usando lo stesso oggetto Statement statement.executeupdare(...); // 8 tris) riprendo la transazione distribuita resource.start(identifier, XAResource.TMRESUME); 100 di 182

101 JDBC & SSL 101 di 182

102 Connessioni SSL PostgreSQL supporta nativamente le connessioni tramite SSL/TLS da parte dei client (si veda il capitolo 16 del manuale). Solitamente il server PostgreSQL accetta sia connessioni in chiaro che cifrate sulla stessa porta, negoziando dinamicamente il tipo di connessione ricevuta. Una connessione in chiaro invia i pacchetti (es. le query e i risultati) senza cifrarli, e quindi questi sono osservabili sulla rete. Una connessione SSL utilizza uno schema di cifratura per rendere illeggibili da terzi i pacchetti in transito. 102 di 182

103 Connessioni SSL: impostazioni del server Il server deve essere stato compilato con il supporto per SSL, e i certificati devono essere stati generati e si devono trovare nella directory $PGDATA. 103 di 182

104 Connessioni SSL: test Per verificare il funzionamento del supporto SSL è possibile usare il client da riga di comando. Di default viene usata una connessione in chiaro La suite di cifratura è disponibile (connessione esplicita a localhost) 104 di 182

105 Java & SSL Ci sono due modi principali di utilizzo di SSL nelle connessioni a PostgreSQL: connessione verificata: il certificato del server è stato correttamente importato nel keystore (personale o di sistema) di Java, ad indicare che il certificato è noto e corretto. In tal caso, il driver JDBC di PostgreSQL effettua i controlli necessari per validare il certificato ed evitare attacchi man-in-the-middle. connessione non verificata: non è possibile importare il certificato nel keystore, e quindi ci si fida al volo (con i rischi che ne derivano) del certificato presentato dal server. In questo caso occorre usare una socket factory messa a disposizione dal driver JDBC di PostgreSQL. 105 di 182

106 Connessione verificata Il driver JDBC di PostgreSQL si occupa di tutta la parte di scambio di chiavi e connessione, ma occorre importare il certificato del server nel keystore: (1) il certificato del server deve essere tradotto in una forma che keytool può comprendere. A tal fine lo si converte come file DER (ASN1-DER; formato senza header) dal formato PEM (standard per openssl, presenta un header testuale). 106 di 182

107 Connessione verificata (2) il certificato deve essere importato nel keystore (in questo caso privato dell'utente). Al certificato viene associata l'alias pgday, che rappresenta una sorta di username (in realtà è il proprietario del certificato). Il keystore generato, essendo usato per la verifica di un'identità e non strettamente per la cifratura, viene anche denominato trustore. 107 di 182

108 Connessione verificata (3) l'url di connessione deve contenere il parametro ssl=true, al fine di indicare al driver di usare la connessione SSL (viene usata la factory socket di default). Connection connection = DriverManager.getConnection( "jdbc:postgresql://localhost/pgday?loglevel=2&ssl=true", "luca", "fluca"); (4) occorre specificare come parametri alla JVM quale keystore usare e quale password. [luca@fluca:~]$ java Djavax.net.ssl.trustStore=$HOME/keystore Djavax.net.ssl.trustStorePassword=aglets it.pgday.lferrari.pgjdbc1 108 di 182

109 Connessione verificata La connessione impiega qualche secondo per essere convertita da normale a cifrata. Il traffico in circolazione non è più in chiaro. 109 di 182

110 Connessione non verificata E' possible stabilire una connessione SSL senza aver verificato (importato) il certificato del server. A tal scopo è sufficiente impostare la factory di socket SSL come parametro della URL di connessione a org.postgresql.ssl.nonvalidatingfactory. Non è più necessario specificare il keystore e la sua password. Connection connection = DriverManager.getConnection( "jdbc:postgresql://localhost/pgday?loglevel=2&ssl=true &sslfactory=org.postgresql.ssl.nonvalidatingfactory", "luca", "fluca"); [luca@fluca:~]$ java it.pgday.lferrari.pgjdbc1 110 di 182

111 org.postgresql.driver 111 di 182

112 Registrazione del Driver PostgreSQL Il Driver si auto-registra in modo statico richiamando il metodo (static) registerdriver di DriverManager. La registrazione statica anziché nel costruttore del Driver stesso (come molti alti driver fanno) impedisce una registrazione multipla dello stesso driver all'interno della JVM. static { static { try{ try{ java.sql.drivermanager.registerdriver(new Driver()); java.sql.drivermanager.registerdriver(new Driver()); } } catch (SQLException e) catch (SQLException e) { e.printstacktrace(); } { e.printstacktrace(); } } // org.postgresql.driver } // org.postgresql.driver 112 di 182

113 Come il DriverManager sceglie il Driver appropriato... private static Connection getconnection(string url, Properties info, private static Connection getconnection(string url, Properties info, ClassLoader callercl) throws SQLException { ClassLoader callercl) throws SQLException { java.util.vector drivers = null; java.util.vector drivers = null; synchronized (DriverManager.class){ synchronized (DriverManager.class){ drivers = readdrivers; drivers = readdrivers; } } SQLException reason = null; SQLException reason = null; for (int i = 0; i < drivers.size(); i++) { for (int i = 0; i < drivers.size(); i++) { DriverInfo di = (DriverInfo)drivers.elementAt(i); DriverInfo di = (DriverInfo)drivers.elementAt(i); Connection result = di.driver.connect(url, info); Connection result = di.driver.connect(url, info); if (result!= null) { if (result!= null) { class DriverInfo { return (result); class DriverInfo { return (result); Driver driver; } Driver driver; } Class driverclass; // codice di gestione Class driverclass; // codice di gestione String driverclassname; // errori... String driverclassname; // errori... } // java.sql.drivermanager }} } // java.sql.drivermanager }} // java.sql.drivermanager // java.sql.drivermanager 113 di 182

114 connect(..) Il metodo connect(..) del driver PostgreSQL effettua la connessione effettiva al database: si verifica che l'url di connessione sia gestibile ed appropriato tramite il metodo acceptsurl(..); se non è stato specificato un timeout di login viene tentata la connessione direttamente nel thread chiamante (metodo makeconnection(..)); se è stato specificato un timeout di login viene creato un nuovo thread (ConnectionThread), che cercherà di effettuare la connessione (metodo run()) mentre il thread chiamante resterà in attesa per un tempo pari al timeout specificato (metodo getresult(..)). 114 di 182

115 connect(..) public java.sql.connection connect(string url, Properties info) public java.sql.connection connect(string url, Properties info) throws SQLException { throws SQLException { try { // se non ho nessun timeout tento la connessione try { // se non ho nessun timeout tento la connessione // direttamente (opzione di default) // direttamente (opzione di default) long timeout = timeout(props); long timeout = timeout(props); if (timeout <= 0) if (timeout <= 0) return makeconnection(url, props); return makeconnection(url, props); // tento la connessione tramite un altro thread // tento la connessione tramite un altro thread ConnectThread ct = new ConnectThread(url, props); ConnectThread ct = new ConnectThread(url, props); new Thread(ct, new Thread(ct, "PostgreSQL JDBC driver connection thread").start(); "PostgreSQL JDBC driver connection thread").start(); return ct.getresult(timeout); return ct.getresult(timeout); } catch (PSQLException ex1) { } catch (PSQLException ex1) { throw ex1; throw ex1; } catch (Exception ex2) { } catch (Exception ex2) { throw new PSQLException(...); throw new PSQLException(...); } } }} // org.postgresql.driver // org.postgresql.driver 115 di 182

116 PGStream: un oggetto magico PGStream rappresenta un wrapper attorno connessione verso il database PostgreSQL. ad una Esso contiene un riferimento ad un oggetto java.net.socket che rappresenta la connessione al database e agli stream per la lettura e la scrittura dei dati su tale socket (sottoclassi specifiche di OutpuStream e InputStream). PGStream mette a disposizione dei metodi di utilità per la scrittura/lettura di byte, interi (2,4 byte), char, stringhe, etc. che vengono usati per l'invio di informazioni secondo il protocollo di comunicazione V2 o V di 182

117 Interfacce particolari QueryExecutor: gestisce i messaggi specifici di una versione di protocollo (es. V3) per l'esecuzione di query. Una implmentazione è ad esempio org.postgresql.core.v3.queryexecutorimpl. ResultHandler: gestisce la costruzione progressiva di ResultSet (aggiunge una tupla man mano che viene ricevuta dalla rete), warning ed errori. SimpleQuery: gestione dei dati di una query singola. 117 di 182

118 Comunicazione FrontEnd-BackEnd La comunicazione fra il lato applicativo (FrontEnd driver) e il server (BackEnd) avviene tramite l'uso di un protocollo a scambio di messaggi. Il protocollo, giunto alla sua terza revisione (PostgreSQL >= 7.4) viene comunemente denominato protocollo V di 182

119 Protocollo V3: formato dei messaggi Un messaggio è un pacchetto contenente diversi byte rappresentati l'informazione. message_type (1 byte) length (4 bytes) content (length 4 bytes) il primo byte del messaggio identifica il tipo del messaggio stesso i successivi quattro byte specificano la lunghezza del messaggio stesso (incluso il dato di lunghezza stesso) i rimanenti byte rappresentano contenuto del messaggio il 119 di 182

120 PreparedStatement vs Portal La fase di parse genera un PreparedStatement, ossia un oggetto che rappresenta l'interpretazione lessicale di una query. Tale oggetto subirà poi il bind dei parametri venendo promosso in un Portal, un oggetto pronto ad eseguire la query. Sostanzialmente un Portal è un handle per una query pronta da eseguire o che sta eseguendo, una sorta di cursore (che funziona anche per query non SELECT). Un portale puo' essere identificato da un nome, oppure rimanere unnamed se si usa il portale di default. 120 di 182

121 Protocollo V3: Simple & Extended Query Il protocollo prevede due modalità principali di funzionamento: Simple Query: viene inviato un messaggio con la query e questa viene immediatamente eseguita; i risultati vengono poi inviati al frontend. Extended Query: viene inviata la query ma non viene eseguita immediatamente. In una fase successiva si fa il bind dei parametri della query, si esegue la query e si inviano i risultati al frontend. Simple Query : Statement = Extended Query : PreparedStatement 121 di 182

122 Simple Query BackEnd FrontEnd Query contiene la string SQL della query da eseguire RowDescription indica il layout delle colonne ritornate dalla query RowData dati di una singola riga RowData RowData ReadyForQuery indica che il backend è pronto ad accettare una nuova query 122 di 182

123 Extended Query BackEnd FrontEnd Parse (stringa SQL, [nome prepared statement, nome portale]) ParseComplete Bind (lista parametri, [nome prepared statement, nome portale]) BindComplete Execute ([nome portale]) RowData dati di una singola riga RowData RowData Sync sincronizzazione per errori ReadyForQuery il backend è pronto 123 di 182

124 Query: overview Viene creato un oggetto Statement dal Connection corrente. Tipicamente si passa attraverso AbstractJdbc2Connection, che richiama il tipo di connessione corretto (es. Jdbc4Connection). Il metodo executequery(..) viene sempre richiamato su AbstractJdbc2Statement, che mediante QueryExecutor ottiene un oggetto SimpleQuery che implementa il protocollo di comunicazione FrontEnd e BackEnd opportuno (es. v3). 124 di 182

125 Query: overview Il metodo execute(..) di AbstractJdbc2Statement accetta l'oggetto query da eseguire e richiama il metodo execute(..) sul QueryExecutor. Al metodo viene anche passato un oggetto ResultHandler che si occupa di gestire risultati (ResultSet), errori e warning. Il QueryExecutor invia i messaggi necessari al server, in particolare tramite il metodo sendquery(..) e sendonequery(..) invia la query da eseguire in formato testuale. 125 di 182

126 Query: overview Il QueryExecutor processa la risposta del server tramite processresult(..). Questo metodo utilizza l'oggetto PGStream per leggere i messaggi in arrivo dal server. Viene usato un meccanismo ad eventi: a seconda del messaggio letto viene richiamato un metodo opportuno sul ResultHandler. In questo modo l'handler può, ad esempio, memorizzare le tuple man mano che vengono lette. Si richiede al ResultHandler di restituire il ResultSet. Questo viene ritornato indietro lungo lo stack fino al lato applicativo. 126 di 182

127 Creazione di uno Statement public java.sql.statement createstatement() throws SQLException { public java.sql.statement createstatement() throws SQLException { // crea uno statement per un Resultset classico // crea uno statement per un Resultset classico return createstatement(java.sql.resultset.type_forward_only, return createstatement(java.sql.resultset.type_forward_only, java.sql.resultset.concur_read_only); java.sql.resultset.concur_read_only); }} // org.postgresql.jdbc2.abstractjdbc2connection // org.postgresql.jdbc2.abstractjdbc2connection public java.sql.statement createstatement(int resultsettype, public java.sql.statement createstatement(int resultsettype, int resultsetconcurrency, int resultsetholdability) int resultsetconcurrency, int resultsetholdability) throws SQLException { throws SQLException { // creazione di uno statement di livello 4 // creazione di uno statement di livello 4 Jdbc4Statement s = new Jdbc4Statement(this, resultsettype, Jdbc4Statement s = new Jdbc4Statement(this, resultsettype, resultsetconcurrency, resultsetholdability); resultsetconcurrency, resultsetholdability); s.setpreparethreshold(getpreparethreshold()); s.setpreparethreshold(getpreparethreshold()); return s; return s; }} // org.postgresql.jdbc4.jdbc4connection // org.postgresql.jdbc4.jdbc4connection La creazione di uno Statement implica ancora una volta il passaggio fra le classi dei vari livelli JDBC. In particolare si parte dal livello 2 (il minimo) e si arriva fino al livello 4 creando un Jdbc4Statement. 127 di 182

128 Esecuzione di una query public ResultSet executequery(string p_sql) throws SQLException { public ResultSet executequery(string p_sql) throws SQLException { // se ho una query preprata (PreparedStament) non processare // se ho una query preprata (PreparedStament) non processare // un'altra query SQL (p_sql) // un'altra query SQL (p_sql) if (preparedquery!= null) if (preparedquery!= null) throw new PSQLException(...); throw new PSQLException(...); // eseguo la query specificata // eseguo la query specificata if (!executewithflags(p_sql, 0)) if (!executewithflags(p_sql, 0)) throw new PSQLException(...); throw new PSQLException(...); // sono stati ritornati troppi result set in una sola volta // sono stati ritornati troppi result set in una sola volta if (result.getnext()!= null) if (result.getnext()!= null) throw new PSQLException(...); throw new PSQLException(...); return (ResultSet)result.getResultSet(); return (ResultSet)result.getResultSet(); }} // org.postgresql.jdbc2.abstractjdbc2statement // org.postgresql.jdbc2.abstractjdbc2statement Il metodo fondamentale per l'esecuzione di una query è executewithflags. Mediante tale metodo viene creato un oggetto SimpleQuery che si occuperà dello scambio di messaggi con il backend per il protocollo relativo. 128 di 182

129 Esecuzione di una query public boolean executewithflags(string p_sql, int flags) public boolean executewithflags(string p_sql, int flags) throws SQLException { throws SQLException { // controlla se lo statement è chiuso (nel caso solleva // controlla se lo statement è chiuso (nel caso solleva // una eccezione) // una eccezione) checkclosed(); checkclosed(); // effettua alcune sostituzione nella query (es. escaping) // effettua alcune sostituzione nella query (es. escaping) p_sql = replaceprocessing(p_sql); p_sql = replaceprocessing(p_sql); Query simplequery = Query simplequery = connection.getqueryexecutor().createsimplequery(p_sql); connection.getqueryexecutor().createsimplequery(p_sql); execute(simplequery, null, QueryExecutor.QUERY_ONESHOT flags); execute(simplequery, null, QueryExecutor.QUERY_ONESHOT flags); this.lastsimplequery = simplequery; this.lastsimplequery = simplequery; // result è un tipo ResultWrapper, che contiene // result è un tipo ResultWrapper, che contiene // anche il ResultSet // anche il ResultSet return (result!= null && result.getresultset()!= null); return (result!= null && result.getresultset()!= null); }} // org.postgresql.jdbc2.abstractjdbc2statement // org.postgresql.jdbc2.abstractjdbc2statement public Query createsimplequery(string sql) { public Query createsimplequery(string sql) { return parsequery(sql, false); return parsequery(sql, false); }} // org.postgresql.core.v3.queryexecutorimpl // org.postgresql.core.v3.queryexecutorimpl 129 di 182

130 Esecuzione di una query protected void execute(query querytoexecute, protected void execute(query querytoexecute, ParameterList queryparameters, int flags) throws SQLException { ParameterList queryparameters, int flags) throws SQLException { // chiusura di query precedenti e pulizia di warning ed errori // chiusura di query precedenti e pulizia di warning ed errori // che potevano provenire da query precedenti // che potevano provenire da query precedenti StatementResultHandler handler = new StatementResultHandler(); StatementResultHandler handler = new StatementResultHandler(); result = null; result = null; connection.getqueryexecutor().execute(querytoexecute, connection.getqueryexecutor().execute(querytoexecute, queryparameters, queryparameters, handler, handler, maxrows, maxrows, fetchsize, fetchsize, flags); flags); result = firstunclosedresult = handler.getresults(); result = firstunclosedresult = handler.getresults(); }} // org.postgresql.jdbc2.abstractjdbc2statement // org.postgresql.jdbc2.abstractjdbc2statement Si prepara un handler per il risultato ed eventuali errori e si passa la query e l'handler al metodo execute(..) del QueryExecutor (la sua implementazione per il protocollo V3) affinché gestisca i messaggi. 130 di 182

131 Esecuzione di una query (lettura risultati) protected void processresults(resulthandler handler, int flags) protected void processresults(resulthandler handler, int flags) throws IOException { throws IOException { Vector tuples = new Vector(); Field[] fields = null; Vector tuples = new Vector(); Field[] fields = null; while (!endquery) { while (!endquery) { c = pgstream.receivechar(); c = pgstream.receivechar(); switch (c){ switch (c){ case 'D': // messaggio di tipo DataRow case 'D': // messaggio di tipo DataRow Object tuple = null; Object tuple = null; try { try { tuple = pgstream.receivetuplev3(); tuple = pgstream.receivetuplev3(); } catch(outofmemoryerror oome) {... } } catch(outofmemoryerror oome) {... } if (!noresults) if (!noresults) tuples.addelement(tuple); tuples.addelement(tuple); break; break; // org.postgresql.core.v3.queryexecutorimpl // org.postgresql.core.v3.queryexecutorimpl 131 di 182

132 Esecuzione di una query (lettura risultati) case 'C': // command status (fine esecuzione execute) case 'C': // command status (fine esecuzione execute) String status = receivecommandstatus(); String status = receivecommandstatus(); if (fields!= null tuples!= null) { if (fields!= null tuples!= null) { handler.handleresultrows(currentquery, fields, tuples, null); handler.handleresultrows(currentquery, fields, tuples, null); fields = null; tuples = null; fields = null; tuples = null; } } else else interpretcommandstatus(status, handler); interpretcommandstatus(status, handler); break; break; case 'Z': // ready for query case 'Z': // ready for query receiverfq(); receiverfq(); endquery = true; // termina il ciclo while endquery = true; // termina il ciclo while // pulizia degli oggetti in memoria e delle code // pulizia degli oggetti in memoria e delle code break; break; } } } } }} // org.postgresql.core.v3.queryexecutorimpl // org.postgresql.core.v3.queryexecutorimpl 132 di 182

133 Query: traffico di rete Analizzando il traffico di rete con uno sniffer è possibile vedere i singoli messaggi inviati da e per il server. Nell'esempio qui sopra si nota il messaggio di Parse, con la query inviata, seguito da vari messaggi uno dei quali Execute. 133 di 182

134 Query: traffico di rete In questo caso si vede il messaggio RowDescription che precede una serie di messaggi DataRow, ciascuno con indicazione del numero, lunghezza e valore delle colonne. 134 di 182

135 Query: traffico di rete Messaggio Parse contenente la query e il nome dello statement di riferimento sul server (null). Il server invia un RowDescription e di seguito tutte le righe tramite una serie di DataRow. Il server invia i messaggi di chiusura, fra i quali ReadyForQuery. 135 di 182

136 Esecuzione di una query parametrica statement2.setint(1, corsopk); statement2.setint(1, corsopk); // lato applicativo // lato applicativo La fase di bind in memoria prevede che il parametro sia associato alla sua posiziona nella query (index), al suo valore (rappresentato come stringa) e al suo tipo (OID) affinché il BackEnd possa capire come trattare il dato stesso. I parametri sono contenuti in oggetti che implementano ParameterList a seconda del protocollo utilizzato (ad es. V3ParameterList). public void setint(int parameterindex, int x) throws SQLException { public void setint(int parameterindex, int x) throws SQLException { checkclosed(); checkclosed(); bindliteral(parameterindex, Integer.toString(x), Oid.INT4); bindliteral(parameterindex, Integer.toString(x), Oid.INT4); }} private void bindliteral(int paramindex,string s,int oid) private void bindliteral(int paramindex,string s,int oid) throws SQLException { throws SQLException { if(adjustindex) if(adjustindex) paramindex ; paramindex ; // registro il parametro in un contenitore V3ParameterList // registro il parametro in un contenitore V3ParameterList preparedparameters.setliteralparameter(paramindex, s, oid); preparedparameters.setliteralparameter(paramindex, s, oid); } // org.postgresql.jdbc2.abstractjdbc2statement } // org.postgresql.jdbc2.abstractjdbc2statement 136 di 182

137 Esecuzione di una query parametrica Il metodo executequery(), invocato dopo il bind dei parametri, richiama il metodo executewithflags(..) già visto in precedenza e usato anche per query non parametriche. Ripercorrendo lo stack di chiamata si giunge a QueryExecutor.execute(..) che questa volta ha impostato i parametri della query. Da qui si passa poi a QueryExecutor.sendOneQuery(..) che provvede a sostituire ad ogni parametro (indicato con?) un $n (con n valore della posizione partendo da 1). In coda alla query compare poi l'array degli OID dei tipi dei parametri. public java.sql.resultset executequery() throws SQLException { public java.sql.resultset executequery() throws SQLException { if (!executewithflags(0)) if (!executewithflags(0)) throw new PSQLException(...); throw new PSQLException(...); if (result.getnext()!= null) if (result.getnext()!= null) throw new PSQLException(...); throw new PSQLException(...); return (ResultSet) result.getresultset(); return (ResultSet) result.getresultset(); } // org.postgresql.jdbc2.abstractjdbc2statement } // org.postgresql.jdbc2.abstractjdbc2statement FE=> Parse(stmt=null,query="SELECT cognome, nome FE=> Parse(stmt=null,query="SELECT cognome, nome FROM partecipante WHERE corsopk=$1",oids={23}) FROM partecipante WHERE corsopk=$1",oids={23}) 137 di 182

138 Esecuzione di una query parametrica private void sendbind(simplequery query, SimpleParameterList params, private void sendbind(simplequery query, SimpleParameterList params, Portal portal) throws IOException { Portal portal) throws IOException { // informazioni su portale e statement (se esistono) // informazioni su portale e statement (se esistono) String statementname = query.getstatementname(); String statementname = query.getstatementname(); byte[] encodedstatementname = query.getencodedstatementname(); byte[] encodedstatementname = query.getencodedstatementname(); byte[] encodedportalname = (portal == null? null : byte[] encodedportalname = (portal == null? null : portal.getencodedportalname()); portal.getencodedportalname()); pgstream.sendchar('b'); pgstream.sendchar('b'); // messaggio Bind // messaggio Bind pgstream.sendinteger4((int)encodedsize); // dimensione messaggio pgstream.sendinteger4((int)encodedsize); // dimensione messaggio if (encodedportalname!= null) // eventuale portale if (encodedportalname!= null) // eventuale portale pgstream.send(encodedportalname); pgstream.send(encodedportalname); pgstream.sendchar(0); pgstream.sendchar(0); if (encodedstatementname!= null) if (encodedstatementname!= null) pgstream.send(encodedstatementname); pgstream.send(encodedstatementname); // eventuale statement // eventuale statement pgstream.sendchar(0); pgstream.sendchar(0); // org.postgresql.core.v3.queryexecutorimpl // org.postgresql.core.v3.queryexecutorimpl 138 di 182

139 Esecuzione di una query parametrica // invio tipo e numero dei parametri // invio tipo e numero dei parametri for (int i = 1; i <= params.getparametercount(); ++i) for (int i = 1; i <= params.getparametercount(); ++i) pgstream.sendinteger2(params.isbinary(i)? 1 : 0); pgstream.sendinteger2(params.isbinary(i)? 1 : 0); pgstream.sendinteger2(params.getparametercount()); pgstream.sendinteger2(params.getparametercount()); for (int i = 1; i <= params.getparametercount(); ++i) { for (int i = 1; i <= params.getparametercount(); ++i) { if (params.isnull(i)) if (params.isnull(i)) pgstream.sendinteger4( 1); // dimensione 1 => NULL pgstream.sendinteger4( 1); // dimensione 1 => NULL else { else { // dimensione del parametro // dimensione del parametro pgstream.sendinteger4(params.getv3length(i)); pgstream.sendinteger4(params.getv3length(i)); try{ // valore del parametro try{ // valore del parametro params.writev3value(i, pgstream); params.writev3value(i, pgstream); }catch (PGBindException be) { }catch (PGBindException be) { bindexception = be; bindexception = be; } } } } } } } // org.postgresql.core.v3.queryexecutorimpl } // org.postgresql.core.v3.queryexecutorimpl 139 di 182

140 Esecuzione di INSERT/UPDATE I passi fondamentali sono simili a quanto visto in precedenza: si deve ottenere (AbstractJdbc2Connection) (AbstractJdbc2Statement); dall'oggetto uno Connection Statement si richiede allo Statement (AbstractJdbc2Statement) di eseguire la modifica mediante il metodo JDBC executeupdate(string sql); si ottiene come valore di ritorno il numero di record modificati nella base di dati (command status) Il command status viene interpretato letteralmente, ossia dalla stringa di command status inviata dal BackEnd si estraggono i valori ritornati dal server. 140 di 182

141 Esecuzione di un INSERT/UPDATE public int executeupdate(string p_sql) throws SQLException { public int executeupdate(string p_sql) throws SQLException { // eseguo la query tramite il QueryExecutor // eseguo la query tramite il QueryExecutor // non mi aspetto risultati (QUERY_NO_RESULTS) // non mi aspetto risultati (QUERY_NO_RESULTS) if (executewithflags(p_sql, QueryExecutor.QUERY_NO_RESULTS)) if (executewithflags(p_sql, QueryExecutor.QUERY_NO_RESULTS)) // non dovrei avere alcun risultato // non dovrei avere alcun risultato throw new PSQLException(...); throw new PSQLException(...); // restituisco il numero di record aggiornati/inseriti // restituisco il numero di record aggiornati/inseriti return getupdatecount(); return getupdatecount(); } // org.postgresql.jdbc2.asbtractjdbc2statement } // org.postgresql.jdbc2.asbtractjdbc2statement public boolean executewithflags(string p_sql, int flags) public boolean executewithflags(string p_sql, int flags) throws SQLException { throws SQLException { Query simplequery = Query simplequery = connection.getqueryexecutor().createsimplequery(p_sql); connection.getqueryexecutor().createsimplequery(p_sql); execute(simplequery, null, QueryExecutor.QUERY_ONESHOT flags); execute(simplequery, null, QueryExecutor.QUERY_ONESHOT flags); this.lastsimplequery = simplequery; this.lastsimplequery = simplequery; return (result!= null && result.getresultset()!= null); return (result!= null && result.getresultset()!= null); }} // org.postgresql.jdbc2.asbtractjdbc2statement // org.postgresql.jdbc2.asbtractjdbc2statement 141 di 182

142 Esecuzione di un INSERT/UPDATE protected void processresults(resulthandler handler, int flags) protected void processresults(resulthandler handler, int flags) throws IOException { throws IOException { case 'C': // Command Status (end of Execute) case 'C': // Command Status (end of Execute) // ottiene la stringa risultato dell'esecuzione della query // ottiene la stringa risultato dell'esecuzione della query // ad esempio INSERT 0 1 oppure UPDATE 1 // ad esempio INSERT 0 1 oppure UPDATE 1 String status = receivecommandstatus(); String status = receivecommandstatus(); if (fields!= null tuples!= null){ if (fields!= null tuples!= null){ // qui c'e' un ResultSet, quindi una select // qui c'e' un ResultSet, quindi una select handler.handleresultrows(currentquery, fields, tuples, null); handler.handleresultrows(currentquery, fields, tuples, null); fields = null; tuples = null; fields = null; tuples = null; } } else { else { // qui non c'e' ResultSet, quindi una scrittura sul DB // qui non c'e' ResultSet, quindi una scrittura sul DB interpretcommandstatus(status, handler); interpretcommandstatus(status, handler); } } } // org.postgresql.core.v3.queryexecutorimpl } // org.postgresql.core.v3.queryexecutorimpl 142 di 182

143 Pl/Java 143 di 182

144 Installazione di Pl/Java Pljava si basa su un modulo del kernel denominato pljava.so; la versione base è compilata per architettura 32 bit e verso PostgreSQL 8.3. Per una corretta installazione su piattaforme e database differenti occorre: usare un JDK fra la versione 4 e 5 (non la 6 perché cambiano le API JDBC); installare gli header per lo sviluppo di PostgreSQL della versione corrente (ad esempio postgresql server dev 8.4); scaricare tramite CVS l'ultima versione dei sorgenti di Pl/Java; verificare che JAVA_HOME e il PATH puntino al compilatore Java corretto; lanciare la compilazione con il comando make. 144 di 182

145 Installazione di Pl/Java Occorre poi apportare alcune modifiche a postgresql.conf affinché il server-cluster postmaster possa caricare l'estensione Java: dynamic_library_path = '$libdir:/sviluppo/java/pljava/org.postgresql.pljava/build/objs' custom_variable_classes = 'pljava' pljava.classpath='/sviluppo/java/pljava/org.postgresql.pljava/build /pljava.jar' 145 di 182

146 Introduzione a Pl/Java Pl/Java è una estensione di PostgreSQL per supportare il linguaggio Java come linguaggio interno. Pl/Java è simile, concettualmente, ad altri Pl/xxx come ad esempio Pl/Perl. La differenza principale con altri linguaggi è che, essendo Java compilato, non è possibile scrivere direttamente codice Java all'interno del server, bensì si deve istruire il server per richiamare del codice Java in formato bytecode. In altre parole usare Pl/Java significa sempre: Scrivere del codice Java. Scrivere del codice SQL per richiamare Java. 146 di 182

147 JNI? Il backend PostgreSQL non è scritto in Java! Occorre quindi trovare un modo per far dialogare un pezzo di codice Java con il backend. Ci sono due soluzioni possibili: RPC JNI Pl/Java si basa su JNI per svariate ragioni, principalmente: Piu' semplice ed efficiente Il codice Java risiede sul server, quindi è locale al backend (non c'è necessità di usare chiamate remote) 147 di 182

148 1 backend = 1 JVM? // backend.c static void initializejavavm(void){... jstat = JNI_createVM(&s_javaVM, &vm_args);... } Nel file backend.c, che inizializza il collegamento fra il backend vero e proprio e Java, si ha che per ogni connessione viene avviata una JVM tramite JNI. In sostanza si ha una JVM per ogni connessione utente. Ciò è coerente con il design di PostgreSQL che prevede un processo (backend appunto) per ogni connessione utente, inoltre garantisce la protezione dello spazio utente tramite l'astrazione dei processi e infine consente di gestire la priorità dei processi stessi tramite gli strumenti del sistema operativo (ps, nice,...). 148 di 182

149 Installazione di Pl/Java PlJava viene fornito con uno strumento (Java) per l'installazione del supporto Java presso un determinato database: deploy.jar. Occorre eseguire questo programma Java (che richiede la presenza del driver JDBC PostgreSQL) per installare il supporto dinamico a Java nel database: java org.postgresql.pljava.deploy.deployer install database hrpmdb user postgres password postgres Il programma provvede a creare le funzioni handler e lo schema speciale sqlj nel database. 149 di 182

150 Vedere cosa succede dietro le quinte E' bene abilitare il livello di log_min_messages a debug3 per ottenere un po' di informazioni circa l'utilizzo di Java nel server. Nei log si troveranno messaggi circa la creazione dell'istanza della JVM e il caricamento delle classi :55:03 CEST DEBUG: find_in_dynamic_libpath: trying "/usr/lib/postgresql/8.4/lib/pljava" :55:03 CEST DEBUG: find_in_dynamic_libpath: trying "/sviluppo/java/pljava/org.postgresql.pljava/build/objs/pljava" :55:03 CEST DEBUG: find_in_dynamic_libpath: trying "/usr/lib/postgresql/8.4/lib/pljava.so" :55:03 CEST DEBUG: find_in_dynamic_libpath: trying "/sviluppo/java/pljava/org.postgresql.pljava/build/objs/pljava.so" :55:03 CEST DEBUG: Using integer_datetimes :55:03 CEST DEBUG: Added JVM option string " Djava.class.path=/sviluppo/java/pljava/org.postgresql.pljava/build" :55:03 CEST DEBUG: Added JVM option string " Dsqlj.defaultconnection=jdbc:default:connection" :55:03 CEST DEBUG: Added JVM option string "vfprintf" :55:03 CEST DEBUG: Added JVM option string " Xrs" :55:03 CEST DEBUG: Creating JavaVM :55:03 CEST DEBUG: JavaVM created :55:03 CEST DEBUG: Getting Backend class pljava.jar 150 di 182

151 Un primo esempio di funzione CREATE FUNCTION getsysprop(varchar) RETURNS VARCHAR AS 'java.lang.system.getproperty' LANGUAGE java; 151 di 182

152 Scrivere funzioni PL/Java Ogni metodo invocabile in PostgreSQL deve essere un metodo statico (i parametri devono corrispondere a quelli passati alla funzione SQL). Ogni funzione Java deve essere invocata tramite una funzione SQL. Le classi devono essere contenute in un file jar caricato e impostato nel classpath del database. Il classpath viene amministratori. gestito solo dagli utenti ATTENZIONE: se vengono riportate eccezioni di sicurezza significa che la classe è presente nel classpath del processo postmaster e quindi viene caricata senza passare dal motore database! 152 di 182

153 Un secondo esempio di funzione 153 di 182

154 Parametri e tipi di ritorno: un esempio 154 di 182

155 NULL vs null Il tipo NULL del linguaggio SQL viene tradotto nel tipo null di Java. Però per SQL è lecito avere NULL anche dove c'è uno scalare, mentre per Java no! Di conseguenza le funzioni che lavorino con scalari (in ingresso/uscita) e che debbano gestire tipi NULL (SQL) devono usare le classi wrapper. 155 di 182

156 Funzioni che restituiscono un SETOF Pl/Java richiede che una funzione che ritorna un SETOF (lato SQL) restituisca un Iterator (lato Java). Non verranno accettati altri tipi di ritorno! E' comunque possibile usare un qualunque tipo di dato/struttura che implementi l'interfaccia Iterator. 156 di 182

157 Creazione di Trigger Il codice Java dipende dalle librerie Pl/Java Ogni funzione trigger non restituisce nulla (void) e accetta come parametro un oggetto TriggerData con le informazioni sull'invocazione del Trigger. Tramite TriggerData è possibile selezionare il result set new oppure old e su questi agire (old è in sola lettura). 157 di 182

158 Esempio di Trigger Si vuole creare un trigger che modifichi una stringa di testo con le metainformazioni sul trigger stesso. 158 di 182

159 Esempio di Trigger 159 di 182

160 Esempio piu' complesso di Trigger Si supponga di voler tenere traccia del numero globali di invocazioni della funzione trigger, del numero di update di una riga e di impedire le cancellazioni delle righe che sono state aggiornate un numero pari di volte. 160 di 182

161 Codice della funzione Trigger public class Trigger { public static int globalcounter = 0; public static void triggerjavamethod( TriggerData triggerdata ) throws SQLException{ // e' un trigger per update? if( triggerdata.isfiredbyupdate() ){ // prelevo il result set nuovo ResultSet newrs = triggerdata.getnew(); // prelevo il vecchio result set ResultSet oldrs = triggerdata.getold(); // inserisco il contatore globale newrs.updateint("global_counter", ++globalcounter); // incremento il contatore di update newrs.updateint("update_counter", oldrs.getint("update_counter") + 1); } else if( triggerdata.isfiredbydelete() ){ ResultSet oldrs = triggerdata.getold(); if( ( oldrs.getint("update_counter") % 2 ) == 0 ) throw new TriggerException(triggerData, "Tupla non.."); } } Non esiste ancora un metodo efficace per gestire l'abort di un trigger! Lanciare una eccezione non funziona appieno: blocca la transazione nel backend! 161 di 182

162 Esecuzione del Trigger 162 di 182

163 Maneggiare tipi complessi I tipi complessi devono essere trattati tramite un ResultSet aggiornabile. Si rinuncia al paradigma OOP per passare ad un paradigma in stile record-based. E' comodo usare un ResultSetGenerator: La funzione (lato SQL) richiama un metodo (lato Java) statico che restituisce un oggetto che implementa l'interfaccia ResultSetProvider. ResultSetProvider contiene due metodi: assignrowvalues(..) che permette l'update di una cella (riga/colonna) nel ResultSet e close() usato per rilasciare le risorse. ResultSetProvider.assignRowValues(..) restituisce false se non ci sono altre righe da processare, true se ancora una riga deve essere inserita nel ResultSet. 163 di 182

164 Maneggiare tipi complessi: generare delle tuple public class RowGenerator implements ResultSetProvider { private static int NUM_ROWS = 10; private static int NUM_COLS = 5; public boolean assignrowvalues(resultset rs, int rownumber) throws SQLException { if( rownumber <= NUM_ROWS ){ for( int j = 1; j <= NUM_COLS; j++ ) rs.updatestring(j, "Riga " + rownumber + " Colonna " + j); return true; } else return false; } public void close() throws SQLException { System.out.println("Chiusura del row set provider"); } public static ResultSetProvider generaterows(){ return new RowGenerator(); } } 164 di 182

165 Maneggiare tipi complessi: invocazioni SQL 165 di 182

166 JDBC & Pl/Java =~ SQL MED E' possibile chiamare JDBC da Pl/Java, in modo da poter interrogare in modo riflessivo il database al quale si è connessi. In questo modo si possono ottenere (e restituire) i dati appartenenti ad altre tabelle/relazioni. 166 di 182

167 JDBC & Pl/Java =~ SQL MED public class RowGenerator implements ResultSetHandle { private String databasename; private String username; private String password; private String tablename; public RowGenerator(String database, String username, String password, String table ){ this.databasename = database; this.username = username; this.password = password; this.tablename = table; } // funzione usata lato SQL public static ResultSetHandle generaterows(string database, String username, String password, String table){ return new RowGenerator( database, username, password, table ); } 167 di 182

168 JDBC & Pl/Java = SQL MED // funzione usata per ottenere le tuple public ResultSet getresultset() throws SQLException { org.postgresql.driver driver = new org.postgresql.driver(); Connection connection = DriverManager.getConnection( this.databasename, this.username, this.password ); Statement statement = connection.createstatement(); return statement.executequery(" SELECT * FROM "+ this.tablename ); } } Se la funzione viene creata come linguaggio untrusted allora è possibile usare la connessione verso ogni database, e quindi implementare un SQL MED completo. ATTENZIONE: i driver devono trovarsi nel classpath! 168 di 182

169 Utilizzo dei SavePoint public static void executeinsert(int counter) throws SQLException{ Connection connection = DriverManager.getConnection("jdbc:default:connection"); Statement statement = connection.createstatement(); Savepoint save = null; // effettuo 10 inserimenti for( int i = 0; i < counter; i++ ){ statement.execute("insert INTO java_table(nome) VALUES('inserimento " + i + "')"); if( i >= (counter / 2) && save == null ) save = connection.setsavepoint(); } // rollback connection.rollback( save ); } 169 di 182

170 SavePoint: risultato 170 di 182

171 Listener private static Logger logger = Logger.getAnonymousLogger(); public static void executeinsert(int counter) throws SQLException{ Connection connection = DriverManager.getConnection("jdbc:default:connection"); Session session = SessionManager.current(); session.addsavepointlistener( new SavepointListener() { public void onstart(session arg0, Savepoint arg1, Savepoint arg2) throws SQLException { logger.info("savepoint START " + arg0 + " savepoints " + arg1 + " " + arg2); } public void oncommit(session arg0, Savepoint arg1, Savepoint arg2) throws SQLException { logger.info("savepoint COMMIT" + arg0 + " savepoints " + arg1 + " " + arg2); } public void onabort(session arg0, Savepoint arg1, Savepoint arg2) throws SQLException { logger.info("savepoint ABORT " + arg0 + " savepoints " + arg1 + " " + arg2); } }); 171 di 182

172 Listener E' possibile agganciare dei listener per le transazioni (TransactionListener) e per la gestione dei SavePoint (sotto-transazioni) (SavePointListener). 172 di 182

173 JDBC & Pl/Java =~ SQL MED public class RowGenerator implements ResultSetHandle { private String databasename; private String username; private String password; private String tablename; public RowGenerator(String database, String username, String password, String table ){ this.databasename = database; this.username = username; this.password = password; this.tablename = table; } public static ResultSetHandle generaterows(string database, String username, String password, String table){ return new RowGenerator( database, username, password, table ); } public ResultSet getresultset() throws SQLException { Connection connection = DriverManager.getConnection( this.databasename, this.username, this.password ); Statement statement = connection.createstatement(); return statement.executequery(" SELECT * FROM "+ this.tablename ); } } 173 di 182

174 Singleton e PooledObjects Pl/Java consente la gestione di oggetti in un pool, ovvero un recipiente di oggetti che possono essere riciclati per scopi futuri. In un certo senso questo aiuta nel paradigma dei singleton. Ogni oggetto che deve essere gestibile da un pool deve implementare l'interfaccia PooledObject e implementare i metodi per la attivazione e disattivazione. Il costruttore dell'oggetto deve accettare il pool di appartenenza (ObjectPool) sul quale puo' operare. 174 di 182

175 Esempio di PooledObject public class Pooled implements PooledObject{ private long creationtimemillis; private ObjectPool mypool; public Pooled( ObjectPool mypool ){ super(); this.creationtimemillis = Calendar.getInstance().getTimeInMillis(); this.mypool = mypool; } public void activate() throws SQLException { System.out.println("Oggetto <" + creationtimemillis + "> attivato!"); } public void passivate() throws SQLException { System.out.println("Oggetto <" + creationtimemillis + "> disattivato!"); } 175 di 182

176 Esempio di PooledObject public void remove() { System.out.println("Oggetto <" + creationtimemillis + "> rimosso!"); } public static void createpooledobject() throws SQLException{ // ottengo la sessione corrente Session session = SessionManager.current(); // ottengo il pool di oggetti ObjectPool pool = session.getobjectpool( Pooled.class ); // ottengo una istanza dal pool Pooled mypooled = (Pooled) pool.activateinstance(); // ci faccio qualcosa... // poi lo reinserisco nel pool pool.passivateinstance(mypooled); } } 176 di 182

177 Esempio di PooledObject Se si invoca ripetutamente la funzione di generazione dell'oggetto si nota che è sempre lo stesso oggetto ad essere usato. Se l'oggetto non viene reinserito nel pool, allora un nuovo viene creato e usato. 177 di 182

178 Multithreading Problema: Java è un linguaggio che supporta il multithreading, ma il backend PostgreSQL è un singolo processo senza supporto ai thread. Il supporto al multithreading di Java deve essere comunque garantito! Se si pensa al backend come ad un ennesimo thread, allora tutti i thread (Java e di backend) devono sincronizzarsi in modo coerente: si utilizza un singolo lock! Viene definito un oggetto particolare, Backend.THREADLOCK sul quale tutti si sincronizzano. il 178 di 182

179 Backend.THREADLOCK 179 di 182

JDBC. A. Bechini 2004. Accesso a DataD con Java

JDBC. A. Bechini 2004. Accesso a DataD con Java JDBC Accesso a DataD atabase ase con Java Utilizzo di DB da applicazioni esterne Un DB contiene e gestisce dati, importanti per varie operazioni supportate da applicazioni software Come può un applicazione

Dettagli

Introduzione JDBC interfaccia java.sql driver caricare i driver

Introduzione JDBC interfaccia java.sql driver caricare i driver J D B C DISPENSE Introduzione JDBC (Java Database Connectivity) è un interfaccia completamente Java utilizzata per eseguire istruzioni SQL sui database. L'API JDBC si trova nel pacchetto java.sql; contiene

Dettagli

CORSO DI ALGORITMI E PROGRAMMAZIONE. JDBC Java DataBase Connectivity

CORSO DI ALGORITMI E PROGRAMMAZIONE. JDBC Java DataBase Connectivity CORSO DI ALGORITMI E PROGRAMMAZIONE JDBC Java DataBase Connectivity Anno Accademico 2002-2003 Accesso remoto al DB Istruzioni SQL Rete DataBase Utente Host client Server di DataBase Host server Accesso

Dettagli

Non si deve fare ALCUN riferimento alla parte specifica di JDBC.

Non si deve fare ALCUN riferimento alla parte specifica di JDBC. Un applicazione per la quale sia fondamentale l indipendenza dal Database può essere scritta in Java usando le specifiche. (Package java.sql) Non devono essere usate chiamate specifiche del database: Si

Dettagli

Programmazione Java Avanzata Spring - JDBC

Programmazione Java Avanzata Spring - JDBC Programmazione Java Avanzata Spring - JDBC Ing. Gianluca Caminiti Riferimenti Spring http://www.springsource.org/ (scaricate il reference) Beginning Spring 2 - From Novice to Professional. APress. 2008

Dettagli

Siti web centrati sui dati Architettura MVC-2: i JavaBeans

Siti web centrati sui dati Architettura MVC-2: i JavaBeans Siti web centrati sui dati Architettura MVC-2: i JavaBeans 1 ALBERTO BELUSSI ANNO ACCADEMICO 2009/2010 Limiti dell approccio SEVLET UNICA La servlet svolge tre tipi di funzioni distinte: Interazione con

Dettagli

JDBC per l accesso Java a DB. Tito Flagella tito@link.it

JDBC per l accesso Java a DB. Tito Flagella tito@link.it JDBC per l accesso Java a DB Tito Flagella tito@link.it JDBC fornisce una libreria standard per l accesso a database relazionali Non è un acronimo ufficiale ma è comunemente interpretato come Java DataBase

Dettagli

Architettura MVC-2: i JavaBeans

Architettura MVC-2: i JavaBeans Siti web centrati sui dati Architettura MVC-2: i JavaBeans Alberto Belussi anno accademico 2008/2009 Limiti dell approccio SEVLET UNICA La servlet svolge tre tipi di funzioni distinte: Interazione con

Dettagli

JDBC versione base. Le classi/interfacce principali di JDBC

JDBC versione base. Le classi/interfacce principali di JDBC JDBC versione base Java Database Connectivity è il package Java per l accesso a database relazionali il package contiene interfacce e classi astratte uno dei pregi è la completa indipendenza del codice

Dettagli

Sviluppo Applicazioni Mobile Lezione 12 JDBC. Dr. Paolo Casoto, Ph.D - 2012

Sviluppo Applicazioni Mobile Lezione 12 JDBC. Dr. Paolo Casoto, Ph.D - 2012 + Sviluppo Applicazioni Mobile Lezione 12 JDBC + Cosa vediamo nella lezione di oggi Oggi analizzeremo insieme una specifica tecnologia Java per l accesso e la manipolazione di basi di dati relazionali

Dettagli

Basi di dati. Il Linguaggio SQL. K. Donno - Il Linguaggio SQL

Basi di dati. Il Linguaggio SQL. K. Donno - Il Linguaggio SQL Basi di dati Il Linguaggio SQL Data Definition Language (DDL) Data Definition Language: insieme di istruzioni utilizzate per modificare la struttura della base di dati Ne fanno parte le istruzioni di inserimento,

Dettagli

Esercitazione su JDBC

Esercitazione su JDBC Esercitazione su JDBC Basi di Dati L Ingegneria dei Processi Gestionali (Ilaria Bartolini - Roberto Cabras) come usare SQL (1) Le istruzioni SQL possono essere eseguite interattivamente Ese JDBC 2 come

Dettagli

Laboratorio di reti II: Gestione di database lato server

Laboratorio di reti II: Gestione di database lato server Laboratorio di reti II: Gestione di database lato server Stefano Brocchi brocchi@dsi.unifi.it 23 marzo, 2009 Stefano Brocchi Laboratorio di reti II: Database 23 marzo, 2009 1 / 32 Uso di database lato

Dettagli

SQL. Laboratorio di Progettazione di Basi di Dati (CdS in Informatica e TPS)

SQL. Laboratorio di Progettazione di Basi di Dati (CdS in Informatica e TPS) 1 SQL Laboratorio di Progettazione di Basi di Dati (CdS in Informatica e TPS) a.a. 2014/2015 http://www.di.uniba.it/~lisi/courses/basi-dati/bd2014-15.htm Dott.ssa Francesca A. Lisi dott.ssa Francesca A.

Dettagli

Esercitazione 4 JDBC

Esercitazione 4 JDBC JDBC Obiettivi dell esercitazione Familiarizzare con l'organizzazione dell'ambiente di lavoro per la realizzazione di applicazioni Java Utilizzare i costrutti di base della libreria JDBC per 1. la gestione

Dettagli

JDBC di base. Le classi/interfacce principali di JDBC

JDBC di base. Le classi/interfacce principali di JDBC JDBC di base Java Database Connectivity è il package Java per l accesso a database relazionali il package contiene interfacce e classi astratte completa indipendenza del codice dal tipo di database o di

Dettagli

Scheda 15 Accedere ai DataBase con JDBC

Scheda 15 Accedere ai DataBase con JDBC Scheda 15 Accedere ai DataBase con JDBC G IOVANNI PULITI Panoramica: che cosa è JDBC La API JDBC, introdotta per la prima volta con il JDK 1.0, è una API che permette di accedere a database relazionali

Dettagli

Dispensa di database Access

Dispensa di database Access Dispensa di database Access Indice: Database come tabelle; fogli di lavoro e tabelle...2 Database con più tabelle; relazioni tra tabelle...2 Motore di database, complessità di un database; concetto di

Dettagli

HBase Data Model. in più : le colonne sono raccolte in gruppi di colonne detti Column Family; Cosa cambia dunque?

HBase Data Model. in più : le colonne sono raccolte in gruppi di colonne detti Column Family; Cosa cambia dunque? NOSQL Data Model HBase si ispira a BigTable di Google e perciò rientra nella categoria dei column store; tuttavia da un punto di vista logico i dati sono ancora organizzati in forma di tabelle, in cui

Dettagli

PROVA FINALE Ingegneria del software

PROVA FINALE Ingegneria del software PROVA FINALE Ingegneria del software Ing. Jody Marca jody.marca@polimi.it Laboratorio N 4 Cos è JDBC 2 JDBC significa Java Database Connectivity Standard definito da Sun MicroSystems per connettere programmi

Dettagli

Manuale Amministratore Legalmail Enterprise. Manuale ad uso degli Amministratori del Servizio Legalmail Enterprise

Manuale Amministratore Legalmail Enterprise. Manuale ad uso degli Amministratori del Servizio Legalmail Enterprise Manuale Amministratore Legalmail Enterprise Manuale ad uso degli Amministratori del Servizio Legalmail Enterprise Pagina 2 di 16 Manuale Amministratore Legalmail Enterprise Introduzione a Legalmail Enterprise...3

Dettagli

19. LA PROGRAMMAZIONE LATO SERVER

19. LA PROGRAMMAZIONE LATO SERVER 19. LA PROGRAMMAZIONE LATO SERVER Introduciamo uno pseudocodice lato server che chiameremo Pserv che utilizzeremo come al solito per introdurre le problematiche da affrontare, indipendentemente dagli specifici

Dettagli

Java: la libreria delle classi

Java: la libreria delle classi Java: la libreria delle classi Applet anatomia di un applet cenni di html La libreria JDBC per l accesso ai database il package java.sql 213 Applet Un applet è una applicazione Java che ha una forma particolare

Dettagli

2.5. L'indirizzo IP identifica il computer di origine, il numero di porta invece identifica il processo di origine.

2.5. L'indirizzo IP identifica il computer di origine, il numero di porta invece identifica il processo di origine. ESERCIZIARIO Risposte ai quesiti: 2.1 Non sono necessarie modifiche. Il nuovo protocollo utilizzerà i servizi forniti da uno dei protocolli di livello trasporto. 2.2 Il server deve essere sempre in esecuzione

Dettagli

Server Galileo. http://galileo.dmi.unict.it/

Server Galileo. http://galileo.dmi.unict.it/ Server Galileo http://galileo.dmi.unict.it/ Gestione progetti Wiki Subversion Iscrizione a Galileo Per registrarsi è sufficiente iscriversi da questa pagina: https://galileo.dmi.unict.it/iscrizioni/ L'account

Dettagli

Data Base. Master "Bio Info" Reti e Basi di Dati Lezione 6

Data Base. Master Bio Info Reti e Basi di Dati Lezione 6 Data Base 1 Sommario I concetti fondamentali. Database Relazionale.. Query e SQL MySql, Creazione di un db in MySQL con PHPmyAdmin Creazione database e delle Tabelle Query Inserimento Ricerca Modifica

Dettagli

Lezione 9. Applicazioni tradizionali

Lezione 9. Applicazioni tradizionali Lezione 9 Applicazioni tradizionali Pag.1 Sommario Concetti trattati in questa lezione: SQL nel codice applicativo Cursori API native ODBC Pag.2 SQL nel codice applicativo I comandi SQL possono essere

Dettagli

Riccardo Dutto, Paolo Garza Politecnico di Torino. Riccardo Dutto, Paolo Garza Politecnico di Torino

Riccardo Dutto, Paolo Garza Politecnico di Torino. Riccardo Dutto, Paolo Garza Politecnico di Torino Integration Services Project SQL Server 2005 Integration Services Permette di gestire tutti i processi di ETL Basato sui progetti di Business Intelligence di tipo Integration services Project SQL Server

Dettagli

JDBC: Introduzione. Java Database Connectivity (JDBC): parte 1. Schema dei legami tra le classi principali. Principali classi/interfacce di JDBC

JDBC: Introduzione. Java Database Connectivity (JDBC): parte 1. Schema dei legami tra le classi principali. Principali classi/interfacce di JDBC JDBC: Introduzione Java Database Connectivity (JDBC): parte 1 Gianluca Moro DEIS - Università di Bologna gmoro@deis.unibo.it Java Database Connectivity è il package Java per l accesso a database relazionali

Dettagli

MySQL Database Management System

MySQL Database Management System MySQL Database Management System http://www.mysql.com/ DATABASE RELAZIONALI Un database è una collezione strutturata di informazioni. I database sono delle strutture nelle quali è possibile memorizzare

Dettagli

MDAC. Attualmente la versione disponibile di MDAC è la 2.8 ma faremo riferimento alla 2.6. ADO Active Data Objects ADO OLE DB ODBC

MDAC. Attualmente la versione disponibile di MDAC è la 2.8 ma faremo riferimento alla 2.6. ADO Active Data Objects ADO OLE DB ODBC MDAC MDAC è l acronimo di Microsoft Data Access Component e fa parte della tecnologia Microsoft denominata Universal Data Access (UDA). Mette a disposizione una serie di componenti per l accesso a svariate

Dettagli

Basi di dati e Web (Moduli: Laboratorio e Siti Web centrati sui Dati) Prova scritta del 14 luglio 2008

Basi di dati e Web (Moduli: Laboratorio e Siti Web centrati sui Dati) Prova scritta del 14 luglio 2008 Basi di dati e Web (Moduli: Laboratorio e Siti Web centrati sui Dati) Prova scritta del 14 luglio 2008 Avvertenze: e severamente vietato consultare libri e appunti; chiunque verrà trovato in possesso di

Dettagli

Guida alla registrazione on-line di un DataLogger

Guida alla registrazione on-line di un DataLogger NovaProject s.r.l. Guida alla registrazione on-line di un DataLogger Revisione 3.0 3/08/2010 Partita IVA / Codice Fiscale: 03034090542 pag. 1 di 17 Contenuti Il presente documento è una guida all accesso

Dettagli

Università degli Studi di Bologna Facoltà di Ingegneria. Tecnologie Web L-A A.A. 2014 2015. Esercitazione 08 DAO e Hibernate

Università degli Studi di Bologna Facoltà di Ingegneria. Tecnologie Web L-A A.A. 2014 2015. Esercitazione 08 DAO e Hibernate Università degli Studi di Bologna Facoltà di Ingegneria Tecnologie Web L-A A.A. 2014 2015 Esercitazione 08 DAO e Hibernate Agenda Pattern DAO e framework Hibernate progetto d'esempio relativo alla gestione

Dettagli

11/02/2015 MANUALE DI INSTALLAZIONE DELL APPLICAZIONE DESKTOP TELEMATICO VERSIONE 1.0

11/02/2015 MANUALE DI INSTALLAZIONE DELL APPLICAZIONE DESKTOP TELEMATICO VERSIONE 1.0 11/02/2015 MANUALE DI INSTALLAZIONE DELL APPLICAZIONE DESKTOP TELEMATICO VERSIONE 1.0 PAG. 2 DI 38 INDICE 1. PREMESSA 3 2. SCARICO DEL SOFTWARE 4 2.1 AMBIENTE WINDOWS 5 2.2 AMBIENTE MACINTOSH 6 2.3 AMBIENTE

Dettagli

Al giorno d oggi, i sistemi per la gestione di database

Al giorno d oggi, i sistemi per la gestione di database Introduzione Al giorno d oggi, i sistemi per la gestione di database implementano un linguaggio standard chiamato SQL (Structured Query Language). Fra le altre cose, il linguaggio SQL consente di prelevare,

Dettagli

Consiglio regionale della Toscana. Regole per il corretto funzionamento della posta elettronica

Consiglio regionale della Toscana. Regole per il corretto funzionamento della posta elettronica Consiglio regionale della Toscana Regole per il corretto funzionamento della posta elettronica A cura dell Ufficio Informatica Maggio 2006 Indice 1. Regole di utilizzo della posta elettronica... 3 2. Controllo

Dettagli

GovPay 2.0. Manuale Installazione

GovPay 2.0. Manuale Installazione SERVIZI DI INTERMEDIAZIONE AL NODO DEI PAGAMENTI GovPay-ManualeInstallazione del 16/12/2015 - vers. 1 STATO DEL DOCUMENTO REV. DESCRIZIONE DATA 1 Prima versione 16/12/2015 ATTORI DEL DOCUMENTO Redatto

Dettagli

Database e reti. Piero Gallo Pasquale Sirsi

Database e reti. Piero Gallo Pasquale Sirsi Database e reti Piero Gallo Pasquale Sirsi Approcci per l interfacciamento Il nostro obiettivo è, ora, quello di individuare i possibili approcci per integrare una base di dati gestita da un in un ambiente

Dettagli

GERARCHIE RICORSIVE - SQL SERVER 2008

GERARCHIE RICORSIVE - SQL SERVER 2008 GERARCHIE RICORSIVE - SQL SERVER 2008 DISPENSE http://dbgroup.unimo.it/sia/gerarchiericorsive/ L obiettivo è quello di realizzare la tabella di navigazione tramite una query ricorsiva utilizzando SQL SERVER

Dettagli

Servizi Remoti. Servizi Remoti. TeamPortal Servizi Remoti

Servizi Remoti. Servizi Remoti. TeamPortal Servizi Remoti 20120300 INDICE 1. Introduzione... 3 2. Consultazione... 4 2.1 Consultazione Server Fidati... 4 2.2 Consultazione Servizi Client... 5 2.3 Consultazione Stato richieste... 5 3. Amministrazione... 6 3.1

Dettagli

Corso di Informatica (Programmazione) Lezione 6 (31 ottobre 2008)

Corso di Informatica (Programmazione) Lezione 6 (31 ottobre 2008) Corso di Informatica (Programmazione) Lezione 6 (31 ottobre 2008) Introduzione a Java: primo programma, installazione dell ambiente di sviluppo, compilazione ed esecuzione 1 Introduzione Java è un linguaggio

Dettagli

Volumi di riferimento

Volumi di riferimento Simulazione seconda prova Esame di Stato Gestione di un centro agroalimentare all ingrosso Parte prima) Un nuovo centro agroalimentare all'ingrosso intende realizzare una base di dati per l'attività di

Dettagli

1) GESTIONE DELLE POSTAZIONI REMOTE

1) GESTIONE DELLE POSTAZIONI REMOTE IMPORTAZIONE ESPORTAZIONE DATI VIA FTP Per FTP ( FILE TRANSFER PROTOCOL) si intende il protocollo di internet che permette di trasferire documenti di qualsiasi tipo tra siti differenti. Per l utilizzo

Dettagli

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli CODICE Le fonti in cui si possono trovare tutorial o esempi di progetti utilizzati con Arduino si trovano nel sito ufficiale di Arduino, oppure nei forum di domotica e robotica. Il codice utilizzato per

Dettagli

2104 volume III Programmazione

2104 volume III Programmazione 2103 SQLite Capitolo 77 77.1 Utilizzo generale................................. 2104 77.1.1 Utilizzo di sqlite3».......................... 2104 77.1.2 Copie di sicurezza............................ 2106

Dettagli

SOSEBI PAPERMAP2 MODULO WEB MANUALE DELL UTENTE

SOSEBI PAPERMAP2 MODULO WEB MANUALE DELL UTENTE SOSEBI PAPERMAP2 MODULO WEB MANUALE DELL UTENTE S O. S E. B I. P R O D O T T I E S E R V I Z I P E R I B E N I C U L T U R A L I So.Se.Bi. s.r.l. - via dell Artigianato, 9-09122 Cagliari Tel. 070 / 2110311

Dettagli

PMF Integration Tools

PMF Integration Tools PMF Integration Tools Strumenti di integrazione di PMF con l infrastruttura del cliente Architettura e modalità di interazione Cliente - documentazione - Redatto da Francesco Buratto Redatto il 01/10/2012

Dettagli

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto: Tipi primitivi Il linguaggio Java offre alcuni tipi di dato primitivi Una variabile di tipo primitivo può essere utilizzata direttamente. Non è un riferimento e non ha senso tentare di istanziarla mediante

Dettagli

Automatizzare i compiti ripetitivi. I file batch. File batch (1) File batch (2) Visualizzazione (2) Visualizzazione

Automatizzare i compiti ripetitivi. I file batch. File batch (1) File batch (2) Visualizzazione (2) Visualizzazione Automatizzare i compiti ripetitivi I file batch Anno accademico 2000-01 1 Spesso capita di dover eseguire ripetutatmente una data sequenza di comandi Introdurli uno a uno da tastiera è un processo lento

Dettagli

Corso di Informatica Modulo T3 B2 - Database in rete

Corso di Informatica Modulo T3 B2 - Database in rete Corso di Informatica Modulo T3 B2 - Database in rete 1 Prerequisiti Programmazione web Applicazione web Modello OSI Architettura client/server Conoscenze generali sui database Tecnologia ADO in Visual

Dettagli

PSNET UC RUPAR PIEMONTE MANUALE OPERATIVO

PSNET UC RUPAR PIEMONTE MANUALE OPERATIVO Pag. 1 di 17 VERIFICHE E APPROVAZIONI VERSIONE V01 REDAZIONE CONTROLLO APPROVAZIONE AUTORIZZAZIONE EMISSIONE NOME DATA NOME DATA NOME DATA PRATESI STATO DELLE VARIAZIONI VERSIONE PARAGRAFO O DESCRIZIONE

Dettagli

MANUALE D'USO DEL PROGRAMMA IMMOBIPHONE

MANUALE D'USO DEL PROGRAMMA IMMOBIPHONE 1/6 MANUALE D'USO DEL PROGRAMMA IMMOBIPHONE Per prima cosa si ringrazia per aver scelto ImmobiPhone e per aver dato fiducia al suo autore. Il presente documento istruisce l'utilizzatore sull'uso del programma

Dettagli

Gestione Risorse Umane Web

Gestione Risorse Umane Web La gestione delle risorse umane Gestione Risorse Umane Web Generazione attestati di partecipazione ai corsi di formazione (Versione V03) Premessa... 2 Configurazione del sistema... 3 Estrattore dati...

Dettagli

Corso di PHP. Prerequisiti. 6.1 PHP e il web 1. Conoscenza HTML Tecnica della programmazione Principi di programmazione web

Corso di PHP. Prerequisiti. 6.1 PHP e il web 1. Conoscenza HTML Tecnica della programmazione Principi di programmazione web Corso di PHP 6.1 PHP e il web 1 1 Prerequisiti Conoscenza HTML Tecnica della programmazione Principi di programmazione web 2 1 Introduzione In questa Unità illustriamo alcuni strumenti di programmazione

Dettagli

Tabelle di riferimento Pulsanti Inserire documento Predisposizione doc Approvazione Doc Numerazione Doc Pubblicazione Albo Webservice

Tabelle di riferimento Pulsanti Inserire documento Predisposizione doc Approvazione Doc Numerazione Doc Pubblicazione Albo Webservice - Albo pretorio virtuale e gestione della consultazione documentale - Argomenti Tabelle di riferimento Pulsanti Inserire documento Predisposizione doc Approvazione Doc Numerazione Doc Pubblicazione Albo

Dettagli

Banca dati Professioniste in rete per le P.A. Guida all uso per le Professioniste

Banca dati Professioniste in rete per le P.A. Guida all uso per le Professioniste Banca dati Professioniste in rete per le P.A. Guida all uso per le Professioniste versione 2.1 24/09/2015 aggiornamenti: 23-set-2015; 24-set-2015 Autore: Francesco Brunetta (http://www.francescobrunetta.it/)

Dettagli

MANUALE EDICOLA 04.05

MANUALE EDICOLA 04.05 MANUALE EDICOLA 04.05 Questo è il video che si presenta avviando il programma di Gestione Edicola. Questo primo video è relativo alle operazioni di carico. CARICO Nello schermo di carico, in alto a sinistra

Dettagli

Esercitazione sulle libpq - libreria C per PostgreSQL

Esercitazione sulle libpq - libreria C per PostgreSQL Esercitazione sulle libpq - libreria C per PostgreSQL Roberto Tronci roberto.tronci@diee.unica.it Basi di Dati A.A. 2007/2008 Tronci ( roberto.tronci@diee.unica.it ) Esercitazione libpq Basi di Dati 2007/2008

Dettagli

Do-Dots Protocollo di comunicazione

Do-Dots Protocollo di comunicazione Do-Dots Protocollo di comunicazione Ultimo aggiornamento 10 maggio 2011 rev3 Spiegazioni 10/05/2011 rev2 Primo aggiornamento con attuali comandi 03/05/2011 rev1 - Stesura iniziale 14/05/2010 DOCUMENTO

Dettagli

per immagini guida avanzata Uso delle tabelle e dei grafici Pivot Geometra Luigi Amato Guida Avanzata per immagini excel 2000 1

per immagini guida avanzata Uso delle tabelle e dei grafici Pivot Geometra Luigi Amato Guida Avanzata per immagini excel 2000 1 Uso delle tabelle e dei grafici Pivot Geometra Luigi Amato Guida Avanzata per immagini excel 2000 1 Una tabella Pivot usa dati a due dimensioni per creare una tabella a tre dimensioni, cioè una tabella

Dettagli

DDL, VINCOLI D INTEGRITÁ, AGGIORNAMENTI E VISTE. SQL è più di un semplice linguaggio di interrogazione

DDL, VINCOLI D INTEGRITÁ, AGGIORNAMENTI E VISTE. SQL è più di un semplice linguaggio di interrogazione SQL DDL, VINCOLI D INTEGRITÁ, AGGIORNAMENTI E VISTE SQL è più di un semplice linguaggio di interrogazione! Linguaggio di definizione dati (Data-definition language, DDL):! Crea/distrugge/modifica relazioni

Dettagli

Modulo 4: Ereditarietà, interfacce e clonazione

Modulo 4: Ereditarietà, interfacce e clonazione Modulo 4: Ereditarietà, interfacce e clonazione Argomenti Trattati: Classi, Superclassi e Sottoclassi Ereditarietà Ereditarietà ed Attributi Privati Override super Ereditarietà e Costruttori Polimorfismo

Dettagli

I file di dati. Unità didattica D1 1

I file di dati. Unità didattica D1 1 I file di dati Unità didattica D1 1 1) I file sequenziali Utili per la memorizzazione di informazioni testuali Si tratta di strutture organizzate per righe e non per record Non sono adatte per grandi quantità

Dettagli

Mac Application Manager 1.3 (SOLO PER TIGER)

Mac Application Manager 1.3 (SOLO PER TIGER) Mac Application Manager 1.3 (SOLO PER TIGER) MacApplicationManager ha lo scopo di raccogliere in maniera centralizzata le informazioni piu salienti dei nostri Mac in rete e di associare a ciascun Mac i

Dettagli

Concetto di Funzione e Procedura METODI in Java

Concetto di Funzione e Procedura METODI in Java Fondamenti di Informatica Concetto di Funzione e Procedura METODI in Java Fondamenti di Informatica - D. Talia - UNICAL 1 Metodi e Sottoprogrammi Mentre in Java tramite le classi e gli oggetti è possibile

Dettagli

flusso delle informazioni... 2 password... 3 password/2... 3 inserimento di una nuova richiesta... 4 le condizioni di vendita... 6

flusso delle informazioni... 2 password... 3 password/2... 3 inserimento di una nuova richiesta... 4 le condizioni di vendita... 6 istruzioni per l inserimento di una richiesta on line di prodotti speciali flusso delle informazioni... 2 password... 3 password/2... 3 inserimento di una nuova richiesta... 4 le condizioni di vendita...

Dettagli

Regione Piemonte Portale Rilevazioni Crediti EELL Manuale Utente

Regione Piemonte Portale Rilevazioni Crediti EELL Manuale Utente Pag. 1 di 15 VERS V01 REDAZIONE VERIFICHE E APPROVAZIONI CONTROLLO APPROVAZIONE AUTORIZZAZIONE EMISSIONE NOME DATA NOME DATA NOME DATA A. Marchisio C. Pernumian 29/12/2014 M. Molino 27/02/2015 M. Molino

Dettagli

A intervalli regolari ogni router manda la sua tabella a tutti i vicini, e riceve quelle dei vicini.

A intervalli regolari ogni router manda la sua tabella a tutti i vicini, e riceve quelle dei vicini. Algoritmi di routing dinamici (pag.89) UdA2_L5 Nelle moderne reti si usano algoritmi dinamici, che si adattano automaticamente ai cambiamenti della rete. Questi algoritmi non sono eseguiti solo all'avvio

Dettagli

DBMS ed Applicazioni Motivazioni

DBMS ed Applicazioni Motivazioni DBMS ed Applicazioni Motivazioni Sin ora abbiamo visto SQL come linguaggio per interrogare DBMS da interfaccia interattiva Nella pratica, un efficace sfruttamento delle potenzialità dei DBMS deriva dalla

Dettagli

10.1. Un indirizzo IP viene rappresentato in Java come un'istanza della classe InetAddress.

10.1. Un indirizzo IP viene rappresentato in Java come un'istanza della classe InetAddress. ESERCIZIARIO Risposte ai quesiti: 10.1. Un indirizzo IP viene rappresentato in Java come un'istanza della classe InetAddress. 10.2. Un numero intero in Java è compreso nell'intervallo ( 2 31 ) e (2 31

Dettagli

Manuale utente Volta Control

Manuale utente Volta Control Manuale utente Volta Control www.satellitevolta.com 1 www.satellitevolta.com 2 Volta Control è un tool che permette la progettazione, l implementazione e la gestione di database Cassandra tramite interfaccia

Dettagli

Definizione di domini

Definizione di domini Definizione di domini Come nei linguaggi ad alto livello (es. C) è possibile definire nuovi domini (tipi di dati) a partire da quelli predefiniti, anche se il costruttore è più limitato. create domain

Dettagli

Tecnologia e Applicazioni Internet 2011/12

Tecnologia e Applicazioni Internet 2011/12 Tecnologia e Applicazioni Internet 2011/12 Lezione 4 - Persistenza Matteo Vaccari http://matteo.vaccari.name/ matteo.vaccari@uninsubria.it Perché usare un DB relazionale? Per l accesso concorrente ai dati

Dettagli

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP) 12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP) Programmazione e analisi di dati Modulo A: Programmazione in Java Paolo Milazzo Dipartimento di Informatica,

Dettagli

Guida Rapida all uso del License Manager di ROCKEY4Smart (V. 1.0.10.724)

Guida Rapida all uso del License Manager di ROCKEY4Smart (V. 1.0.10.724) Guida Rapida all uso del License Manager di ROCKEY4Smart (V. 1.0.10.724) Procedo con un esempio: voglio proteggere una applicazione (nell esempio Blocco Note di Windows: notepad.exe) per distribuirla con

Dettagli

Java: Compilatore e Interprete

Java: Compilatore e Interprete Java: Compilatore e Interprete Java Virtual Machine Il bytecode non è Linguaggio Macchina. Per diventarlo, deve subire un ulteriore trasformazione che viene operata dall interprete Java in modalità JIT

Dettagli

Registratori di Cassa

Registratori di Cassa modulo Registratori di Cassa Interfacciamento con Registratore di Cassa RCH Nucleo@light GDO BREVE GUIDA ( su logiche di funzionamento e modalità d uso ) www.impresa24.ilsole24ore.com 1 Sommario Introduzione...

Dettagli

Indice generale. Capitolo 3 Introduzione a PHP...43 Sintassi e istruzioni di base... 45 Variabili, operatori e commenti... 47 Array...

Indice generale. Capitolo 3 Introduzione a PHP...43 Sintassi e istruzioni di base... 45 Variabili, operatori e commenti... 47 Array... Prefazione...xiii A chi si rivolge il libro... xiv Struttura e contenuti del libro... xiv Dove trovare aiuto... xvii Le newsletter di SitePoint... xviii I vostri commenti... xviii Convenzioni adottate

Dettagli

PORTALE CLIENTI Manuale utente

PORTALE CLIENTI Manuale utente PORTALE CLIENTI Manuale utente Sommario 1. Accesso al portale 2. Home Page e login 3. Area riservata 4. Pagina dettaglio procedura 5. Pagina dettaglio programma 6. Installazione dei programmi Sistema operativo

Dettagli

SITI-Reports. Progetto SITI. Manuale Utente. SITI-Reports. ABACO S.r.l.

SITI-Reports. Progetto SITI. Manuale Utente. SITI-Reports. ABACO S.r.l. Progetto SITI Manuale Utente SITI-Reports ABACO S.r.l. ABACO S.r.l. C.so Umberto, 43 46100 Mantova (Italy) Tel +39 376 222181 Fax +39 376 222182 www.abacogroup.eu e-mail : info@abacogroup.eu 02/03/2010

Dettagli

Sviluppata da: Lo Russo - Porcelli Pag. 1 di 6 6FRSR utilizzare il DBMS Postgresql per imparare il linguaggio SQL.

Sviluppata da: Lo Russo - Porcelli Pag. 1 di 6 6FRSR utilizzare il DBMS Postgresql per imparare il linguaggio SQL. Pag. 1 di 6 6FRSR utilizzare il DBMS Postgresql per imparare il linguaggio SQL. 2ELHWWLYL GD UDJJLXQJHUH SHU JOL VWXGHQWL alla fine dell esercitazione gli studenti dovranno essere in grado di: 1. utilizzare

Dettagli

Istruzioni di installazione di IBM SPSS Modeler Text Analytics (licenza per sito)

Istruzioni di installazione di IBM SPSS Modeler Text Analytics (licenza per sito) Istruzioni di installazione di IBM SPSS Modeler Text Analytics (licenza per sito) Le seguenti istruzioni sono relative all installazione di IBM SPSS Modeler Text Analytics versione 15 mediante un licenza

Dettagli

COLLI. Gestione dei Colli di Spedizione. Release 5.20 Manuale Operativo

COLLI. Gestione dei Colli di Spedizione. Release 5.20 Manuale Operativo Release 5.20 Manuale Operativo COLLI Gestione dei Colli di Spedizione La funzione Gestione Colli consente di generare i colli di spedizione in cui imballare gli articoli presenti negli Ordini Clienti;

Dettagli

Laboratorio di Basi di Dati e Web

Laboratorio di Basi di Dati e Web Laboratorio di Basi di Dati e Web Docente: Alberto Belussi Lezione 1 SQL Structured Query Language SQL è stato definito nel 1973 ed è oggi il linguaggio più diffuso per i DBMS relazionali Il linguaggio

Dettagli

Portale tirocini. Manuale utente Per la gestione del Progetto Formativo

Portale tirocini. Manuale utente Per la gestione del Progetto Formativo GESTIONE PROGETTO FORMATIVO Pag. 1 di 38 Portale tirocini Manuale utente Per la gestione del Progetto Formativo GESTIONE PROGETTO FORMATIVO Pag. 2 di 38 INDICE 1. INTRODUZIONE... 3 2. ACCESSO AL SISTEMA...

Dettagli

Procedura SMS. Manuale Utente

Procedura SMS. Manuale Utente Procedura SMS Manuale Utente INDICE: 1 ACCESSO... 4 1.1 Messaggio di benvenuto... 4 2 UTENTI...4 2.1 Gestione utenti (utente di Livello 2)... 4 2.1.1 Creazione nuovo utente... 4 2.1.2 Modifica dati utente...

Dettagli

Cenni di programmazione distribuita in C++ Mauro Piccolo piccolo@di.unito.it

Cenni di programmazione distribuita in C++ Mauro Piccolo piccolo@di.unito.it Cenni di programmazione distribuita in C++ Mauro Piccolo piccolo@di.unito.it Socket Nei sistemi operativi moderni i servizi disponibili in rete si basano principalmente sul modello client/server. Tale

Dettagli

Progettazione : Design Pattern Creazionali

Progettazione : Design Pattern Creazionali Progettazione : Design Pattern Creazionali Alessandro Martinelli alessandro.martinelli@unipv.it 30 Novembre 2010 Progettazione : Design Pattern Creazionali Aspetti generali dei Design Pattern Creazionali

Dettagli

Airone Gestione Rifiuti Funzioni di Esportazione e Importazione

Airone Gestione Rifiuti Funzioni di Esportazione e Importazione Airone Gestione Rifiuti Funzioni di Esportazione e Importazione Airone Funzioni di Esportazione Importazione 1 Indice AIRONE GESTIONE RIFIUTI... 1 FUNZIONI DI ESPORTAZIONE E IMPORTAZIONE... 1 INDICE...

Dettagli

Come modificare la propria Home Page e gli elementi correlati

Come modificare la propria Home Page e gli elementi correlati Come modificare la propria Home Page e gli elementi correlati Versione del documento: 3.0 Ultimo aggiornamento: 2006-09-15 Riferimento: webmaster (webmaster.economia@unimi.it) La modifica delle informazioni

Dettagli

Corso basi di dati Installazione e gestione di PWS

Corso basi di dati Installazione e gestione di PWS Corso basi di dati Installazione e gestione di PWS Gianluca Di Tomassi Email: ditomass@dia.uniroma3.it Università di Roma Tre Cosa è PWS? Il Personal Web Server altro non è che una versione ridotta del

Dettagli

Dipartimento per le Libertà Civili e l Immigrazione

Dipartimento per le Libertà Civili e l Immigrazione Dipartimento per le Libertà Civili e l Immigrazione SUI Sportello Unico Immigrazione Sistema inoltro telematico Manuale utente Versione 9 Data aggiornamento 19/11/2010 17.19.00 Pagina 1 (1) Sommario 1.

Dettagli

Excel. A cura di Luigi Labonia. e-mail: luigi.lab@libero.it

Excel. A cura di Luigi Labonia. e-mail: luigi.lab@libero.it Excel A cura di Luigi Labonia e-mail: luigi.lab@libero.it Introduzione Un foglio elettronico è un applicazione comunemente usata per bilanci, previsioni ed altri compiti tipici del campo amministrativo

Dettagli

Funzioni in C. Violetta Lonati

Funzioni in C. Violetta Lonati Università degli studi di Milano Dipartimento di Scienze dell Informazione Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica Funzioni - in breve: Funzioni Definizione di funzioni

Dettagli

Installazione di GFI WebMonitor

Installazione di GFI WebMonitor Installazione di GFI WebMonitor Requisiti di sistema di GFI WebMonitor Server Microsoft Windows 2000 (SP 3) o 2003. Microsoft ISA 2000 Server (non in modalità solo firewall) OPPURE Server Microsoft ISA

Dettagli

Mida Directory. Introduzione. Mida Directory

Mida Directory. Introduzione. Mida Directory Mida Directory Introduzione MidaDirectory è un applicazione XML per telefoni Cisco, che consente la gestione della rubrica aziendale su display telefonico. Essa permette di consultare i contatti aziendali

Dettagli

1. RETI INFORMATICHE CORSO DI LAUREA IN INGEGNERIA INFORMATICA SPECIFICHE DI PROGETTO A.A. 2013/2014. 1.1 Lato client

1. RETI INFORMATICHE CORSO DI LAUREA IN INGEGNERIA INFORMATICA SPECIFICHE DI PROGETTO A.A. 2013/2014. 1.1 Lato client RETI INFORMATICHE - SPECIFICHE DI PROGETTO A.A. 2013/2014 1. RETI INFORMATICHE CORSO DI LAUREA IN INGEGNERIA INFORMATICA SPECIFICHE DI PROGETTO A.A. 2013/2014 Il progetto consiste nello sviluppo di un

Dettagli

Per chi ha la Virtual Machine: avviare Grass da terminale, andando su Applicazioni Accessori Terminale e scrivere grass

Per chi ha la Virtual Machine: avviare Grass da terminale, andando su Applicazioni Accessori Terminale e scrivere grass 0_Iniziare con GRASS Avvio di Grass e creazione della cartella del Database di GRASS Per chi ha la Virtual Machine: avviare Grass da terminale, andando su Applicazioni Accessori Terminale e scrivere grass

Dettagli