223 γραμμές
18 KiB
Markdown
223 γραμμές
18 KiB
Markdown
+++
|
||
title = 'DataBaseInterface για Perl'
|
||
date = '2000-04-01T00:00:00Z'
|
||
description = ''
|
||
author = 'Μιχάλης Καμπριάνης(mailto:kabrianis@hellug.gr)'
|
||
issue = ['Magaz 23']
|
||
issue_weight = 4
|
||
+++
|
||
|
||
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
*Σε αυτό το μικρό αρθράκι θα κάνουμε μία πρώτη και επιφανειακή προσέγγιση σε προγραματισμό Perl για Databases μέσω του DBI interface*
|
||
|
||
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
Η Perl είναι μία interpreted γλώσσα όπως όλοι ξέρουν. Και ως interpreted θεωρείται από αρκετούς \"κακή\" γλώσσα. Από την άλλη, είναι εξαιρετικά απλή σε σύνταξη.
|
||
Και επειδή είναι εξαιρετικά απλή, υπάρχουν εκατοντάδες προγραμματιστές που την επεκτείνουν, σε τομείς για τους οποίους δεν είχε σχεδιαστεί. Ένας από αυτούς τους
|
||
τομείς είναι οι DataBases.
|
||
|
||
**1. Τι παρέχει το DBI**
|
||
--------------------------------------------------
|
||
|
||
**2. Τι ΔΕΝ παρέχει το DBI**
|
||
------------------------------------------------------
|
||
|
||
**3. Συνηθισμένες συναρτήσεις**
|
||
---------------------------------------------------------
|
||
|
||
- [3.1 Connect](#ss3.1)
|
||
- [3.2 Select](#ss3.2)
|
||
- [3.3 Insert](#ss3.3)
|
||
- [3.4 Delete](#ss3.4)
|
||
- [3.5 Update](#ss3.5)
|
||
- [3.6 Do αντί για prepare() και execute()](#ss3.6)
|
||
- [3.7 Finsh και Disconnect](#ss3.7)
|
||
|
||
**4. \`Αλλα καλούδια**
|
||
------------------------------------------------
|
||
|
||
**5. Βιβλιογραφία**
|
||
---------------------------------------------
|
||
|
||
|
||
### [1. Τι παρέχει το DBI]{#s1}
|
||
|
||
Το module DBI (Database Interface) παρέχει τη δυνατότητα στην perl να μιλάει με μία database. Το module αυτό παρέχει κάποιες functions οι οποίες μιλάνε με
|
||
κάποιο underlying module, το οποίο λέγεται DBD. Υπάρχει ξεχωριστό DBD για κάθε βάση δεδομένων (π.χ. MySQL, Postgres, Oracle κλπ), και δεν παρέχουν όλα τις ίδιες
|
||
δυνατότητες, αλλά με την χρήση του DBI είσαστε λίγο-πολύ σίγουροι ότι ο κώδικας σας μεταφέρεται από την μία Database στην άλλη, χωρίς να ξαναγραφτούν όλες οι
|
||
functions από την αρχή. Ειδικά αν η SQL που γράφετε είναι \"κανονική\" SQL και όχι specific-database-enhanced SQL, είναι πολύ εύκολο (από πλευράς προγράμματος
|
||
και μόνο) να αλλάξετε βάση, ή να διανείμετε τον κώδικά σας χωρίς να σας ενδιαφέρει το τί βάση χρησιμοποιεί ο άλλος (αρκεί βέβαια να του ορίσετε το schema που θα
|
||
δημιουργήσει στην βάση του).
|
||
|
||
Βέβαια, αν χρησιμοποιήσετε το DBI για να εκτελέσετε triggers ή stored procedures σε μία βάση (κάτι που γίνεται), δεν μπορείτε να περιμένετε μεγάλη
|
||
μεταφερσιμότητα, κυρίως λόγω του διαφορετικού τρόπου με τον οποίο καλούν τα διάφορα triggers οι βάσεις. Συνεπώς, αν θέλετε να έχετε την ευελιξία να αλλάξετε
|
||
βάση αύριο - μεθαύριο χωρίς να σας βγουν τα μάτια να διαβάζετε καλά όλο τον κώδικα για να βρείτε τα databse-specific κομμάτια, σημειώστε καλά τα σημεία που τα
|
||
χρησιμοποιείτε και στο υπόλοιπο πρόγραμμα\.... stic k to SQL.
|
||
|
||
|
||
### [2. Τι ΔΕΝ παρέχει το DBI]{#s2}
|
||
|
||
Το DBI δεν παρέχει έναν τρόπο να μιλήσετε σε μία βάση χωρίς να ξέρετε SQL. To DBI είναι ένα απλό API, άρα αν δεν ξέρετε πως να σχεδιάσετε / υλοποιήσετε ένα
|
||
RDBMS και πως να αποθηκεύσετε, αλλάξετε, σβήσετε αρχεία με απλή SQL, μην συνεχίσετε να διαβάζετε, το άρθρο αυτό θα σας είναι εντελώς άχρηστο. Αντ\' αυτού
|
||
διαβάστε ένα βιβλίο για SQL πρώτα, και μετά ξαναελάτε.
|
||
|
||
|
||
### [3. Συνηθισμένες συναρτήσεις]{#s3}
|
||
|
||
### [3.1 Connect]{#ss3.1}
|
||
|
||
Για να ξεκινήσουμε να μιλάμε σε μία βάση, πρέπει πρώτα να συνδεθούμε σε αυτή τη βάση. Αυτό γίνεται απλά καλώντας την function \"connect\" του DBI. Όταν την
|
||
καλέσουμε, θα μας επιστρέψει ένα handler (αν επιτύχει βέβαια), και με αυτό το handler θα μιλάμε.
|
||
|
||
Παράδειγμα 1
|
||
$dbh=DBI->connect('DBI:Pg:dbname=dbname user=dbuser password=dbpass');
|
||
|
||
Η παραπάνω γραμμή, απλά συνδέεται σε μία postgres database, στην βάση με όνομα dbname, με username dbuser και password dbpass. Η database στο συγκεκριμένο
|
||
παράδειγμα πρέπει να είναι στο ίδιο μηχάνημα, και να \"ακούει\" στο standard port της Postgres, αλλιώς πρέπει να χρησιμοποιηθούν και οι παράμετροι host= και
|
||
port=. Σωστή προγραμματιστική τακτική λέει ότι πρέπει η μεταβλητή \$dbh πρέπει να έχει οριστεί νωρίτερα, και να ελεγχθεί αν πράγματι έχει τιμή αυτό που
|
||
επιστρέφεται (αν δηλαδή πέτυχε το connect).
|
||
|
||
Αυτή η συγκεκριμένη γραμμή είναι αρκετά διαφορετική από βάση σε βάση. Για παράδειγμα για Oracle, θα έπρεπε να γραφτεί ως εξής
|
||
|
||
Παράδειγμα 2
|
||
$dbh=DBI->connect('DBI:Oracle:dbname', 'dbuser', 'dbpass');
|
||
|
||
και αυτό οφείλεται στο ότι ο κάθε προγραμματιστής ενός DBD δεν ακολουθεί κάποιους κανόνες για το πως περνάει της παραμέτρους στην βάση του.
|
||
|
||
### [3.2 Select]{#ss3.2}
|
||
|
||
Αφού δημιουργήσαμε τη σύνδεση, πλέον στέλνουμε εντολές, στο \$dbh. Αυτό γίνεται σε δύο στάδια (εκτός από κάποιες περιπτώσεις που θα δούμε παρακάτω). Το πρώτο
|
||
στάδιο είναι να \"προετοιμάσουμε\" την εντολή, και το δεύτερο είναι να την εκτελέσουμε. Το να λάβουμε τα δεδομένα είναι άλλη υπόθεση (και τρίτο στάδιο). Για
|
||
παράδειγμα, για να εκτελέσουμε μία τυπική select σε ένα πίνακα, έστω clients, οι εντολές είναι :
|
||
|
||
Παράδειγμα 3
|
||
$entoli = $dbh->prepare('SELECT * FROM clients');
|
||
$entoli->execute();
|
||
|
||
Όσα είπαμε προηγουμένως για σωστή προγραμματιστική τακτική ισχύουν και εδώ (και σε όλο το άρθρο, οπότε θα σταματήσω να τα λέω), και απλά παραλείπονται μια που ο
|
||
καθένας προτιμάει τον δικό του τρόπο δήλωσης μεταβλητών και ελέγχου επιτυχίας της function.
|
||
|
||
Όπως βλέπουμε, η prepare() δίνει την εντολή, η οποία εκτελείται από την execute(). Αν τώρα θέλουμε να επιλέξουμε συγκεκριμένα στοιχεία από τον πίνακα, απλά
|
||
αντικαθιστούμε το \* με τα στοιχεία που θέλουμε. Έστω δηλαδή ότι θέλουμε τα στοιχεία client\_name και client\_tel από τον πίνακα, οι εντολές γίνονται:
|
||
|
||
Παράδειγμα 4
|
||
$entoli = $dbh->prepare('SELECT client_sname, client_tel FROM clients');
|
||
$entoli->execute();
|
||
|
||
Φυσικά, αν θέλουμε να περιορίσουμε την select μπορούμε μέσω του DBI, θέτοντας WHERE clauses. Ο σωστός τρόπος να γίνει αυτός είναι ο εξής:
|
||
|
||
Παράδειγμα 5
|
||
$entoli = $dbh->prepare('SELECT client_tel FROM clients WHERE client_sname = ?');
|
||
$entoli->execute('kabrianis');
|
||
|
||
Η παράμετρος η οποία θα αντικαταστήσει το ερωτηματικό (?) όταν εκτελεστεί η εντολή, είναι η παράμετρος η οποία μπαίνει ως όρισμα στην function execute(). Τελικά
|
||
δηλαδή θα εκτελεστεί στην Database η εντολή:
|
||
|
||
Παράδειγμα 6
|
||
SELECT client_tel FROM clients WHERE client_sname = 'kabrianis'
|
||
|
||
Προφανώς, μπορούμε να έχουμε περισσότερες από μία παραμέτρους στα WHERE clauses, αντικαθιστώντας τα αντίστοιχα ερωτηματικά με τις παραμέτρους, χωρισμένες με
|
||
κόμμα, στην αντίστοιχη execute(). Μπορούμε επίσης να έχουμε και subqueries, όπως:
|
||
|
||
Παράδειγμα 7
|
||
$entoli = $dbh->prepare('SELECT client_tel FROM clients WHERE client_addr = ?
|
||
AND client_sname in (SELECT client_sname FROM clients WHERE client_fname = ?)');
|
||
$entoli->execute('Athina','Michalis');
|
||
|
||
Αν μπερδευτήκατε, ξαναδιαβάστε SQL. Η εντολή είναι απλούστατη, και θα μας βρεί από την βάση μας (πίνακα clients) όσους έχουν διεύθυνση Athina και λέγονται
|
||
Michalis.
|
||
|
||
Όλα αυτά τα αποτελέσματα της SELECT μπορούν να διαβαστούν από εμάς, γραμμή - γραμμή, με την fetchrow\_array() μέθοδο της \$entoli, και βέβαια μας έρχονται σε
|
||
μορφή array. Για παράδειγμα, ο κώδικας του παραδείγματος 4 θα μας επιστρέφει arrays που θα περιέχουν τα client\_sname και client\_tel ως πρώτο και δεύτερο
|
||
στοιχείο του array. Το να τα κρατήσουμε σε μεταβλητές και να τα κάνουμε κάτι, είναι φυσικά εύκολο.
|
||
|
||
Παράδειγμα 8
|
||
while (@apotelesmata = $entoli->fetchrow_array()) {
|
||
$client_sname = $apotelesmata[0];
|
||
$client_tel = $apotelesmata[1];
|
||
##
|
||
## Εδώ κάνουμε κάτι με τα αποτελέσματα που πήραμε
|
||
##
|
||
}
|
||
|
||
### [3.3 Insert]{#ss3.3}
|
||
|
||
Η χρήση της INSERT είναι πολύ απλή, και μοιάζει με αυτή της SELECT. Για παράδειγμα για να βάλουμε άλλη μία γραμμή στον παραπάνω πίνακα (ο οποίος έστω ότι έχει
|
||
πεδία id, client\_sname, client\_fname και client\_addr) θα γράψουμε τα εξής:
|
||
|
||
Παράδειγμα 9
|
||
$entoli = $dbh->prepare('INSERT INTO clients VALUES (?,?,?,?)');
|
||
$entoli->execute($id,$client_sname,$client_fname,$client_addr);
|
||
|
||
Φυσικά εδώ η fetchrow\_array() δεν θα μας επιστρέψει τίποτα. Η ανωτέρω συνάρτηση μπορεί να επεκταθεί όσο θέλετε, με βάση πάντα τα όρια της SQL, προσθέτοντας
|
||
συγκεκριμένες τιμές, σε συγκεκριμένα πεδία (αν το επιτρέπει ο πίνακας που έχετε φτιάξει).
|
||
|
||
### [3.4 Delete]{#ss3.4}
|
||
|
||
Πραγματικά δεν θα περιμένετε κάτι διαφορετικό, έτσι; Ας πάμε κατυεθείαν στον κώδικα:
|
||
|
||
Παράδειγμα 10
|
||
$entoli = $dbh->prepare('DELETE FROM clients WHERE client_sname = ?');
|
||
$entoli->execute($client_sname);
|
||
|
||
και φυσικά, πάλι η fetchrow\_array() δεν θα επιστρέψει τίποτα. Subqueries μπορούν να χρησιμοποιηθούν, για να σβήσουμε συγκεκριμένες γραμμές ενός πίνακα, ακόμα
|
||
και χωρίς να δώσουμε καθόλου εξωτερικά στοιχεία.
|
||
|
||
### [3.5 Update]{#ss3.5}
|
||
|
||
\`Αλλη μία απλή εντολή, η update, έχει ακριβώς την ίδια σύνταξη με την insert και την delete.
|
||
|
||
Παράδειγμα 11
|
||
$entoli = $dbh->prepare('UPDATE clients SET client_tel = ? WHERE client_sname = ?');
|
||
$entoli->execute($client_tel,$client_sname);
|
||
|
||
Όπως είπαμε και πιο πάνω, οι παράμετροι της execute() διαβάζονται σειριακά, και αντικαθιστούν τα ερωτηματικά που βρίσκουν στην prepare(). Αυτό το ξανατονίζω
|
||
γιατί η update είναι ίσως η πιο \"επικίνδυνη\" εντολή, από την άποψη ότι μπορεί εύκολα να κάνεις λάθος, και να μην το καταλάβεις, και να κάνεις update όλες τις
|
||
εγγραφές ενός πίνακα αντί για μία - δύο που ήθελες.
|
||
|
||
### [3.6 Do αντί για prepare() και execute()]{#ss3.6}
|
||
|
||
Για τις εντολές insert, update και delete, οι οποίες ΔΕΝ επιστρέφουν τίποτα, το DBI παρέχει έναν τρόπο να αποφεύγουμε τις πολλές γραμμές κώδικα. Ο τρόπος είναι
|
||
να αντικαταστήσουμε τα prepare(), execute() και finish (που θα δούμε παρακάτω) με την απλή εντολή do.
|
||
|
||
Παράδειγμα 12
|
||
$entoli = $dbh->do('DELETE FROM clients WHERE client_id = 5');
|
||
|
||
Έτσι η εντολή DELETE προετοιμάζεται (prepare()), εκτελείται (execute()) και ο handler \$entoli τερματίζεται (finish) αυτόματα.
|
||
|
||
### [3.7 Finsh και Disconnect]{#ss3.7}
|
||
|
||
Πρέπει πάντα, να τερματίζουμε τον handler της εντολής μετά την εκτέλεσή της, και το fetching των γραμμών που μας επιστρέφει (αν μας επιστρέφει τίποτα φυσικά).
|
||
Συνεπώς, σε όλα τα παραπάνω παραδείγματα, πρέπει να προσθέσετε στο τέλος την γραμμή:
|
||
|
||
$entoli->finish;
|
||
|
||
ενώ πρέπει, όταν τελειώνουμε με την βάση μας, να κλείνουμε τη σύνδεση:
|
||
|
||
$dbh->disconnect;
|
||
|
||
|
||
### [4. \`Αλλα καλούδια]{#s4}
|
||
|
||
Εκτός από τα connect, disconnect, prepare, execute, do, finish και fetchrow\_arrays που είδαμε, υπάρχουν και άλλα καλούδια που παρέχονται από το DBI, τα οποία
|
||
μπορούν να χρησιμοποιηθούν για να κάνουν τη ζωή σας ευκολότερη. Ας κάνουμε μία σύντομη αναφορά σε κάποια (τα πιο χρήσιμα ίσως) από αυτά:
|
||
|
||
- prepare\_cached(): Αν αντί της prepare() χρησιμοποιήσουμε την prepare\_cached, τότε, κάθε φορά που θα εκτελείται ένα execute() με τις ίδιες ακριβώς
|
||
παραμέτρους, δεν θα γίνεται σύνδεση προς τη βάση, αλλά θα μας επιστρέφονται οι τιμές που έχουν γίνει cached κατά την πρώτη φορά.
|
||
- rows: Αν χρησιμοποιήσουμε την \$entoli-\>rows, θα μας επιστραφεί ο αριθμός των γραμμών που στέλνει η βάση μετά από ένα select.
|
||
- bind\_columns(): Αντί της fetchrow\_array() που είδαμε παραπάνω και του while που αναθέτουμε σε κάποιες μεταβλητές, τα στοιχεία του array που μας
|
||
επιστρέφονται, μπορούμε απλά να χρησιμοποιήσουμε την bind\_columns() δίνοντας ως παραμέτρους τα ονόματα των μεταβλητών. Τα δεδομένα από την βάση μας
|
||
έρχονται μέσω της fetch.
|
||
|
||
Το DBI μας παρέχει στην err τον κωδικό λάθους (αν υπάρχει κάποιο) κατά την εκτέλεση της εντολής, στην errstring το μήνυμα λάθους που επιστρέφει η database, και
|
||
στην state το SQLSTATE κωδικό λάθους. Χρήσιμες functions είναι οι trace, trace\_msg και η func.
|
||
|
||
|
||
### [5. Βιβλιογραφία]{#s5}
|
||
|
||
Καλό βιβλίο, και προτεινόμενο για DBI programming (και με κάποια στοιχεία SQL μέσα) είναι το Programming the Perl DBI από τις εκδόσεις O\'Reilly. Μην το ψάξετε
|
||
στον Παπασωτηρίου, δεν το έχει (και το ζητούσα 2 μήνες).\
|
||
Πολύ καλές πληροφορίες δίνει το manual page του DBI του ίδιου.\
|
||
Πρέπει επίσης να διαβάσετε το manual του DBD module της βάσης σας (αν φυσικά έχει ένα τέτοιο). Βιβλία για Perl και SQL ΔΕΝ θα προτείνω εδώ.
|
||
|