PEP: 249
Titolo: Python Database API Specification v2.0
Versione: $Revision: 1555 $
Autore: db-sig@python.org (Python Database SIG)
Editore: mal@lemburg.com (Marc-Andre Lemburg)
Stato: Final
Tipo: Informativo
Sostituisce: 248
Data di rilascio: 07 Apr 1999
Traduttore: David Gervasoni (davideth0@gmail.com) 18 Marzo 2006
Revisione: Meo Bogliolo (meo@bogliolo.name) 23 Marzo 2006

Introduzione

    Questa API e' stata definita per incoraggiare l'uniformita' tra i
    moduli Python usati per accedere ai database. Facendo questo si
    vogliono raggiungere una buona consistenza per una
    piu' semplice comprensione dei moduli, un codice che sia
    piu' portabile su diversi database ed offrire un piu' ampio raggio di
    connettivita' ai database con Python.

    La specifica dell' interfaccia consiste di diverse sezioni:
        
        * Interfaccia del modulo
        * Oggetti Connection
        * Oggetti Cursor
        * Oggetti DBI Helper
        * Oggetti Type e Costruttori
        * Suggerimenti per l'implementazione
        * Principali modifiche dalla 1.0 alla 2.0
        

    Commenti e domande su queste specifiche debbono essere inviate
    al SIG per l'interfacciamento ai database con Python
    (db-sig@python.org).

    Per maggiori informazioni sull'interfacciamento con i database con
    python e per i pacchetti disponibili si veda il Database Topic
    Guide su http://www.python.org/topics/database/.

    Questo documento descrive le specifiche API dei Database in Python 2.0
    ed un insieme di estensioni opzionali comuni. La precedente versione 1.0
    e' comunque disponibile come riferimento, in PEP 248. Gli autori di
    pacchetti sono incoraggiati ad usare questa versione delle specifiche
    come base per le nuove interfacce.


Interfaccia del modulo

    L'accesso al database è reso possibile tramite oggetti di connessione.
    I moduli devono fornire il seguente costruttore per questi:

        connect(parameters...)

            Costruttore per la creazione di una connessione al database.
            Ritorna un oggetto Connection. Richiede un numero di
            parametri che sono dipendenti dal database. [1]
    
    Devono essere definiti questi moduli globali:

        apilevel

            Costante stringa che specifica il livello della API DB supportata.
            Attualmente sono permesse solo le stringhe '1.0' e '2.0'.
            
            Se non specificata, sarà assunto che l'interfaccia si basi sulla
            DataBase-API 1.0. 

        threadsafety 

            Costante intera che specifica il livello di supporto al multithreading
            offerto. I valori possibili sono:
            
                0   i thread non possono condividere il modulo.
                1   i thread possono condividere il modulo ma non le connessioni.
                2   i thread possono condividere il modulo e le connessioni.
                3   i thread possono condividere il modulo, le connessioni e i cursori.

            Condivisione nel contesto soprastante significa che due thread
            possono usare una risorsa senza aver bisogno di implementare un
            meccanismo di lock tramite semafori mutex. Si noti che non sempre si può
            rendere 'a prova di thread' ['thread safe' NdT] una risorsa
            esterna con un controllo degli accessi tramite mutex: la risorsa
            potrebbe fare riferimento a variabili globali o altre risorse
            esterne che sono al di fuori del nostro controllo. 
            
        paramstyle
        
            Costante stringa che specifica il tipo di formattazione del marcatore
            di parametro previsto dall'interfaccia. I valori possibili sono [2]:
            
                'qmark'     con punto interrogativo,
                            p.e. '...WHERE name=?' 
                'numeric'   in stile numerico, posizionale,
                            p.e. '...WHERE name=:1' 
                'named'     per nome,
                            p.e. '...WHERE name=:name' 
                'format'    nel codice di formato della printf ANSI C,
                            p.e. '...WHERE name=%s' 
                'pyformat'  nei codici di formato estesi Python,
                            p.e. '...WHERE name=%(name)s' 

    Il modulo deve rendere disponibile ogni informazione d'errore attraverso
    le eccezioni seguenti o loro sottoclassi: 

        Warning 

            Eccezione sollevata per avvisi importanti, quali troncamento di dati nel
            corso del loro inserimento, ecc. Dev'essere una sottoclasse dell'eccezione
            Python StandardError (definita nel modulo exceptions). 

        Error 
        
            Eccezione che costituisce la classe base di tutte le altre eccezioni
            di errore. La si può utilizzare per catturare tutti gli errori con un
            singolo comando di 'except'. I warning non sono considerati errori
            perciò non debbono usare questa classe come base. Dev'essere una
            sottoclasse dell'eccezione Python StandardError (definita nel modulo
            exceptions). 

        InterfaceError

            Eccezione sollevata per errori legati all'interfaccia più che al database
            stesso. Dev'essere una sottoclasse di Error. 

        DatabaseError

            Eccezione sollevata per errori sul database. Dev'essere una sottoclasse
            di Error.

        DataError 

            Eccezione sollevata per errori dovuti a problemi con dati calcolati
            come divisioni per zero, valori numerici fuori dall'intervallo consentito,
            ecc. Dev'essere una sottoclasse di DatabaseError. 

        OperationalError
        
            Eccezione sollevata per errori legati a operazioni del database non
            necessariamente sotto il controllo del programmatore, per esempio quando
            avviene una disconnessione inaspettata, non viene trovato il nome della
            sorgente dei dati, non è possibile effettuare una transazione, si ha un
            errore di memoria durante l'elaborazione, ecc.
            Dev'essere una sottoclasse di DatabaseError. 

        IntegrityError
        
            Eccezione sollevata quando è interessata l'integrità relazionale del
            database, p.e. fallisce l'ispezione di una chiave esterna. Dev'essere
            una sottoclasse di DatabaseError. 

        InternalError 
            
            Eccezione sollevata per un errore interno del database, p.e. il cursore
            non è più valido, la transazione non è sincronizzata ecc. Dev'essere una
            sottoclasse di DatabaseError. 

        ProgrammingError
        
            Eccezione sollevata in caso si tratti di errori diretti di programmazione,
            p.e. una tabella non viene trovata o è già esistente, c'è un errore di
            sintassi nel comando SQL, è stato specificato un numero errato di
            parametri, ecc. Dev'essere una sottoclasse di DatabaseError. 

        NotSupportedError 

            Eccezione sollevata quando viene usato un metodo o un'API non supportato
            dal database, p.e. viene richiesto un .rollback() su una connessione che
            non supporta le transazioni o le ha disabilitate. Dev'essere una
            sottoclasse di DatabaseError. 

    Questo è lo schema di ereditarietà delle eccezioni: 

        StandardError
        |__Warning
        |__Error
           |__InterfaceError
           |__DatabaseError
              |__DataError
              |__OperationalError
              |__IntegrityError
              |__InternalError
              |__ProgrammingError
              |__NotSupportedError
  
    Nota: I valori di tali eccezioni non sono definiti. Dovrebbero comunque fornire
    all'utente un'idea abbastanza chiara sull'origine del problema. 

    

Oggetti Connection

    Gli Oggetti Connection debbono rispondere ai metodi seguenti: 

        .close()
        
            Chiude la connessione immediatamente (piuttosto che quando __del__ è invocato).
            La connessione sarà inutilizzabile da qui in avanti: in caso venga tentata
            una qualsiasi operazione sulla connessione verrà sollevata un'eccezione
            Error (o una sua sottoclasse). Lo stesso accade a tutti gli oggetti Cursor
            che tentino di usare la connessione. Chiudendo una connessione
            senza effettuare un commit sulle modifiche si causa un rollback implicito sui dati.

        .commit()
        
            Effettua il commit di qualsiasi transazione in sospeso. Si noti che se
            il database supporta nativamente una funzionalità di auto-commit essa
            dev'essere disabilitata all'inizio. L'interfaccia può comprendere un
            metodo per rimetterla in funzione.
            
            I moduli per database che non supportano le transazioni debbono
            comunque implementarlo con funzionalità nulla. 

        .rollback()
        
            Questo metodo è opzionale, dato che non tutti i database offrono supporto
            alle transazioni. [3]
            
            In caso un database supporti le transazioni, questo metodo fa sì che esso
            ritorni allo stato precedente a ogni transazione in sospeso. Chiudere una
            connessione senza prima effettuare il commit delle modifiche provocherà
            l'esecuzione di un rollback implicito. 

        .cursor() 

            Restituisce un nuovo oggetto Cursore utilizzando la connessione. Se il
            database non fornisce supporto diretto al concetto di cursore, il modulo
            dovrà emulare i cursori con altri mezzi realizzando quanto e'
            necessario per soddisfare queste specifiche. [4]

            

Oggetti Cursore

    Questi oggetti rappresentano un cursore del database, usato nella gestione del
    contesto di un'operazione di fetch. Cursori creati dalla stessa connessione
    non sono isolati, ad esempio, qualsiasi cambiamento fatto al database da un cursore
    è immediatamente visibile dall'altro cursore. Cursori creati da differenti connessioni
    possono essere o meno isolati, in base a come è implementata  la gestione delle transazioni (vedi
    anche i metodi di connessione rollback() e commit().)

    Gli oggetti Cursore debbono rispondere ai seguenti metodi e attributi: 

        .description

            È un attributo a sola lettura che consiste di una sequenza di sequenze
            a sette elementi. Ognuna di queste sequenze contiene informazioni che
            descrivono una colonna di risultati: (name, type_code, display_size,
            internal_size, precision, scale, null_ok). I primi due campi (name e
            type_code) sono obbligatori, gli altri cinque sono opzionali e devono
            essere impostati a None se non sono forniti valori significativi.
            
            L'attributo sarà None per
            operazioni che non restituiscono righe, o nel caso non sia stata ancora
            effettuata un'operazione tramite il metodo executeXXX().
            
            type_code può essere interpretato comparandolo agli oggetti Tipo
            specificati più sotto. 

        .rowcount
        
            È un attributo a sola lettura che specifica il numero di righe che
            l'ultimo executeXXX() ha prodotto (per comandi DQL come select)
            o comunque interessato (per comandi DML come update o insert). 
            
            Il valore dell'attributo è pari a -1 nel caso non sia stato eseguito
            alcun executeXXX() sul cursore o il conteggio delle righe dell'ultima
            operazione non sia calcolabile dall'interfaccia. [7]
            
            Nota: Versioni future delle specifiche DB API potrebbero ridefinire
            quest'ultimo caso e far restituire None anziche' -1.

        .callproc(nomeprocedura[,parametri])

            (Questo metodo è opzionale, dato che non tutti i database supportano
            le "stored procedure". [3])
            
            Invoca la stored procedure del database passata con nomeprocedura.
            La sequenza dei parametri deve contenere una voce per ogni argomento
            richiesto dalla procedura. Il risultato della chiamata è restituito
            come copia modificata della sequenza in ingresso. I parametri in
            ingresso non vengono toccati, i parametri in uscita e ingresso/uscita
            vengono eventualmente rimpiazzati con nuovi valori.

            La procedura può anche fornire come risultato un insieme di righe,
            che dev'essere quindi reso disponibile attraverso i metodi standard
            fetchXXX(). 

        .close()
        
            Chiude il cursore al momento (piuttosto che alla chiamata di __del__).
            Il cursore non sarà più utilizzabile da qui in avanti: in caso venga
            tentata una qualsiasi operazione sul cursore verrà sollevata un'eccezione
            Error (o una sua sottoclasse).

        .execute(operazione[,parametri]) 

            Prepara ed esegue un'operazione sul database (interrogazione o comando).
            I parametri possono essere passati come sequenza o dizionario e verranno
            associati a variabili nell'operazione. Le variabili sono specificate in
            una notazione specifica al database (si veda l'attributo di modulo
            paramstyle per i dettagli). [5] 
            
            Il cursore conserverà un riferimento all'operazione. Se lo stesso oggetto
            operazione gli verrà passato nuovamente, il cursore sara' così in grado
            di ottimizzare il suo comportamento. Questo è molto efficace in caso di 
            algoritmi in cui la stessa operazione viene svolta molte volte con 
            parametri diversi. 

            Per garantire la massima efficienza nel riuso di un'operazione è bene
            usare il metodo setinputsizes() per specificare anzitempo i tipi 
            e le dimensioni dei parametri. Un parametro può anche non 
            corrispondere all'informazione definita in tal modo; l'implementazione 
            deve compensare automaticamente, a prezzo di un'eventuale perdita 
            in efficienza.
            
            I parametri possono anche essere specificati come lista di tuple,
            p.e. per inserire più righe in una singola operazione, ma quest'uso 
            è sconsigliato, si deve piuttosto usare executemany().
            
            I valori restituiti non sono definiti.

        executemany(operazione,sequenza_di_parametri)
        
            Prepara un'operazione sul database (interrogazione o comando), 
            quindi la esegue usando tutte le sequenze o dizionari di parametri 
            trovati in sequenza_di_parametri.
            
            I moduli sono liberi di implementare questo metodo usando 
            invocazioni multiple del metodo execute() o usando operazioni 
            con array per far sì che il database processi la sequenza come 
            un tutt'uno in una singola chiamata. 
            
            L'uso di questo metodo per una operazione che produce uno o più set
            di risultati ha un comportamento non stabilito ed e' possibile (ma non richiesto)
            che venga sollevata un'eccezione per indicare che e' stato generato un
            result set.

            A questo metodo si applicano le stesse considerazioni espresse per
            execute().

            I valori restituiti non sono definiti. 

        .fetchone() 

            Preleva la riga seguente dal risultato di un'interrogazione,
            restituendo una singola sequenza oppure None quando non ci sono 
            più dati disponibili. [6]

            In caso l'ultima invocazione di executeXXX() non abbia prodotto
            alcun risultato o non sia ancora stata inoltrata alcuna invocazione, 
            verrà sollevata un'eccezione Error (o una sua sottoclasse). 

        .fetchmany([size=cursor.arraysize])
        
            Preleva l'insieme successivo di righe facenti parti del risultato 
            di un'interrogazione, restituendo una sequenza di sequenze (p.e. 
            una lista di tuple). In caso non siano più disponibili altre righe, 
            viene restituita una sequenza vuota.

            Il numero di righe da prelevare a ogni chiamata è specificato dal 
            parametro. Se non viene passato esplicitamente, sarà l'attributo 
            arraysize del cursore a determinare il numero di righe che verranno 
            prelevate. Il metodo deve tentare di prelevare tante righe quante 
            indicate dal parametro size. Ove questo non fosse possibile perché 
            non ci sono abbastanza righe disponibili, ne verranno restituite in 
            numero minore.

            In caso l'ultima invocazione di executeXXX() non abbia prodotto 
            alcun risultato o non sia ancora stata inoltrata alcuna invocazione, 
            verrà sollevata un'eccezione Error (o una sua sottoclasse). 

            Si noti che ci sono alcune considerazioni da fare circa l'influenza
            del parametro size sulle prestazioni. Per ottenere prestazioni 
            ottimali di solito la cosa migliore è usare l'attributo arraysize. 
            Se viene passato esplicitamente un parametro size, risulta ottimale 
            mantenere lo stesso valore nelle invocazioni successive di fetchmany(). 

        .fetchall()

            Preleva tutte le righe (restanti) dal risultato di una interrogazione,
            restituendole come sequenza di sequenze (p.e. una lista di tuple). Si
            noti che l'attributo arraysize del cursore può influenzare la velocità
            dell'operazione.
            
            In caso l'ultima invocazione di executeXXX() non abbia prodotto alcun 
            risultato o non sia ancora stata inoltrata alcuna invocazione, verrà 
            sollevata un'eccezione Error (o una sua sottoclasse).

        .nextset()
            
            Questo metodo è opzionale, dato che non tutti i database supportano
            risultati multipli. [3]

            Questo metodo farà saltare il cursore al prossimo risultato disponibile,
            scartando tutte le righe rimanenti del risultato corrente. 

            Se non ci sono più altri risultati, il metodo restituisce None.
            In caso contrario restituisce un valore vero, e le chiamate ai
            metodi fetch che seguono restituiranno righe appartenenti al nuovo
            risultato.

            In caso l'ultima invocazione di executeXXX() non abbia prodotto alcun
            risultato o non sia ancora stata inoltrata alcuna invocazione verrà
            sollevata un'eccezione Error (o una sua sottoclasse). 

        .arraysize 

            Questo attributo scrivibile specifica il numero di righe da prelevare 
            in una singola invocazione di fetchmany(). Il valore predefinito è 1,
            il che significa che verrà prelevata una sola riga alla volta.
            
            Le diverse implementazioni devono rispettare questo valore per 
            quanto concerne il metodo fetchmany(), ma sono libere di interagire 
            con il database una singola riga alla volta. Tale valore può essere
            usato anche nell'implementazione di executemany().

        .setinputsizes(sizes) 
        
            Questo attributo può essere usato prima di un executeXXX() 
            per definire in anticipo aree di memoria per i parametri 
            dell'operazione.
            
            sizes è specificato come sequenza, in cui a ogni elemento corrisponde 
            un parametro in ingresso. L'elemento deve essere un oggetto Tipo 
            che corrisponda a quanto verrà usato in ingresso, oppure un intero che
            specifichi la lunghezza massima di una stringa parametro. Se l'elemento
            è None, allora non verrà riservata un'area di memoria predefinita per 
            la colonna corrispondente (utile per nel caso di input molto grossi). 

            Questo metodo deve essere usato prima dell'invocazione di
            executeXXX(). 

            Le varie implementazioni sono libere di non fargli fare in realtà
            nulla e gli utenti possono tranquillamente fare a meno di usarlo. 

        .setoutputsize(size[,column])

            Imposta la dimensione del buffer di una colonna, utile nel caso
            di prelievi di dati voluminosi (p.e. LONG, BLOB, ecc.). La colonna 
            è specificata secondo l'indice nella sequenza risultato. Se non viene
            specificata, allora tali dimensioni di default verranno applicate a 
            tutte le colonne molto ampie del cursore.

            Questo metodo deve essere usato prima dell'invocazione di 
            executeXXX(). 

            Le varie implementazioni sono libere di non fargli fare in realtà 
            nulla e gli utenti possono tranquillamente fare a meno di usarlo. 


Oggetti Tipo e Costruttori

    Molti database hanno bisogno di avere l'input in un particolare formato per 
    associarlo ai parametri di ingresso di un'operazione. Per esempio, se un input 
    è destinato a finire in una colonna DATE allora deve essere 
    fornita al database con stringa di un formato particolare. Problemi simili 
    esistono per colonne rowid
    [indicatore univoco di una riga in una tabella, tipicamente utilizzato nei database NdT]
    o dati binari molto voluminosi (p.e. BLOB o colonne di tipo RAW). 
    Tutto ciò è fonte di potenziali problemi per Python, dato che i parametri per metodo executeXXX()
    non sono tipizzati. Quando il modulo database vede un oggetto stringa Python, non sa se debba
    essere connesso come una semplice colonna CHAR, come un elemento BINARY o come una DATE. 
    
    Per risolvere questo problema, un modulo deve fornire i costruttori definiti più avanti 
    per creare oggetti che possono conservare valori speciali. Quando verranno passati ai 
    metodi del cursore il modulo potrà discernere il tipo appropriato del parametro 
    d'ingresso e connetterlo opportunamente. 

    L'attributo description di un oggetto Cursore restituisce informazioni su ciascuna delle colonne 
    del risultato di un'interrogazione. type_code dev'essere uguale a uno degli oggetti 
    Tipo definiti più. Gli oggetti Tipo possono essere uguali a più di un codice tipo 
    (p.e. DATETIME potrebbe essere uguale ai codici tipo per le colonne date, time e 
    timestamp si veda Suggerimenti per l'implementazione per i dettagli). 

    Il modulo esporta i seguenti costruttori e insiemi a singolo elemento:
    
        Date(anno,mese,giorno)
            
            Questa funzione crea un oggetto che contiene un valore DATE. 
        
        Time(ore,minuti,secondi) 

            Questa funzione crea un oggetto che contiene un valore TIME. 

        Timestamp(anno,mese,giorno,ore,minuti,secondi) 

            Questa funzione crea un oggetto che contiene un valore TIMESTAMP. 

        DateFromTicks(istante) 

            Questa funzione crea un oggetto che contiene un valore DATE che parte da un dato 
            valore di tick (in secondi dall'ora zero del sistema, si veda la documentazione 
            del modulo Python standard time per dettagli). 

        TimeFromTicks(ticks) 

            Questa funzione crea un oggetto che contiene un valore TIME che parte dal numero 
            di tick dato (in secondi dall'ora zero del sistema, si veda la documentazione del 
            modulo Python standard time per dettagli). 

        TimestampFromTicks(ticks) 

            Questa funzione crea un oggetto che contiene un valore TIMESTAMP che parte da un 
            dato valore di tick (in secondi dall'ora zero del sistema, si veda la documentazione 
            del modulo Python standard time per dettagli). 

        Binary(string) 

            Questa funzione crea un oggetto capace di contenere un valore stringa binario (lungo). 

            
        STRING 

            Questo oggetto tipo è usato per descrivere colonne basate su stringhe (p.e. CHAR). 

        BINARY 

            Questo oggetto tipo è usato per descrivere colonne di dati binari (lunghi)
            (p.e. LONG, RAW, BLOB). 

        NUMBER 
            
            Questo oggetto tipo è usato per descrivere colonne numeriche. 

        DATETIME 

            Questo oggetto tipo è usato per descrivere colonne DATE/TIME. 

        ROWID 

            Questo oggetto tipo è usato per descrivere colonne Identificativo. 

    I valori NULL di SQL sono rappresentati in Python da None sia in ingresso che in uscita. 

    Nota: l'uso dei tick Unix per interfacciarsi a database può causare problemi a causa dell'intervallo
    limitato di date che sono in grado di coprire. 


Suggerimenti per l'implementazione

    * I tipi di oggetto consigliati per date e orari sono quelli definiti nel package mxDateTime.
      Esso fornisce tutti i costruttori e i metodi necessari sia a livello Python che C. 

    * Il tipo consigliato per gli oggetti Binary sono i buffer, disponibili come standard in Python a 
      partire dalla versione 1.5.2. Si faccia riferimento alla documentazione Python per i dettagli. 
      Per informazioni sull'interfaccia C si veda Include/bufferobject.h e Objects/bufferobject.c 
      nella distribuzione dei sorgenti Python.
      
    * A partire da Python 2.3, gli autori dei moduli possono anche usare l'oggetto types definito
      nel modulo standard datetime per la gestione di date/tempi.
      Comunque, deve essere chiaro che questo non rende disponibile una API C come mxDateTime,
      il che significa che l'integrazione con moduli per database basati su C è più difficoltosa.

    * Ecco una semplice implementazione dei costruttori per date e orari basati su tick Unix che 
      delegano il lavoro ai costruttori generici:

        import time

        def DateFromTicks(ticks):
            return apply(Date,time.localtime(ticks)[:3])

        def TimeFromTicks(ticks):
            return apply(Time,time.localtime(ticks)[3:6])

        def TimestampFromTicks(ticks):
            return apply(Timestamp,time.localtime(ticks)[:6])

    * Questa classe Python permette di implementare i tipi di oggetti summenzionati anche nel caso 
    in cui il campo type_code dell'attributo description fornisce valori multipli per un oggetto Tipo: 

        class DBAPITypeObject:
            def __init__(self,*values):
                self.values = values
            def __cmp__(self,other):
                if other in self.values:
                    return 0
                if other < self.values:
                    return 1
                else:
                    return -1

      L'oggetto Tipo risultante eguaglia tutti i valori passati al costruttore. 

    * Ecco un pezzetto di codice Python che implementa la gerarchia delle eccezioni definita in precedenza: 
    
        import exceptions

        class Error(exceptions.StandardError):
            pass

        class Warning(exceptions.StandardError):
            pass

        class InterfaceError(Error):
            pass

        class DatabaseError(Error):
            pass

        class InternalError(DatabaseError):
            pass

        class OperationalError(DatabaseError):
            pass

        class ProgrammingError(DatabaseError):
            pass

        class IntegrityError(DatabaseError):
            pass

        class DataError(DatabaseError):
            pass

        class NotSupportedError(DatabaseError):
            pass

    In C si può usare l'API PyErr_NewException(fullname, base, NULL) per creare gli oggetti Eccezione.

    

Estensioni DB API opzionali

    Durante l'esistenza della DB API 2.0, gli autori di moduli hanno
    spesso estero le loro implementazioni oltre quanto richiesto da
    questa specifica DB API. Per aumentare la compatibilità e per
    fornire un percorso chiaro di aggiornamento alle possibili versioni
    future della specifica, questa sezione definisce un insieme di
    estensioni comuni al nucleo della specifica DB API 2.0.

    Come con tutte le opzioni facoltative di DB API, gli autori del modulo
    del database sono liberi di non implementare questi attributi e metodi
    opzionali (usandoli verrà provocata una AttributeError) o raggiunta
    una NotSupportedError nel caso la disponibilità possa essere controllata
    soltanto durante l'esecuzione. 

    È stato proposto di rendere l'uso di queste estensioni facoltativamente
    visibile al programmatore sollevando warning con il meccanismo di warning di Python. Per rendere
    questa caratteristica utile, i messaggi d'avvertimento devono
    essere standardizzati per poterli mascherare. 
    Questi messaggi standard verranno chiamati sotto "Warning Message".

    Cursor Attribute .rownumber

        Questo attributo in sola lettura deve fornire l'indice
        corrente, a partire da 0, del cursore nel set di risultati o None se
        l'indice non può essere determinato.
        
        L'indice può essere visto come indice del cursore in una sequenza
        (il set di risultati).  Le successive operazioni di fetch prenderanno
        la colonne indicizzata da .rownumber nella sequenza.

        Warning Message: "DB-API extension cursor.rownumber used"

    Connection Attributes .Error, .ProgrammingError, etc.

        Tutte le classi d'eccezione definite dalla DB API
        debbono essere rese disponibili sugli oggetti Connection
        come attributi (oltre ad essere disponibili a livello di modulo). 
        
        Questi attributi facilitano il trattamento degli errori negli
        ambienti in multi-collegamento. 

        Warning Message: "DB-API extension connection.<exception> used"

    Cursor Attributes .connection

        Questo attributo in sola lettura ritorna un riferimento al
        Connection object sul quale il cursore è stato creato.
        
        L'attributo semplifica la scrittura di codice polimorfo
        in ambienti in multi-connessione.

        Warning Message: "DB-API extension cursor.connection used"

    Cursor Method .scroll(value[,mode='relative'])

        Sposta il cursore nel result-set alla nuova posizione a secondo dell'impostazione di mode.

        Se mode è 'relative'(di default), il valore è preso come
        uno spostamento rispetto all'attuale posizione nel set di risultato, se 
        il valore di mode e' 'absolute' il valore viene interpretato come una posizione assoluta.
        
        Un IndexError deve essere sollevato nel caso una operazione
        di scroll cerchi di spostare il cursore al di fuori del result set.
        In questo caso la posizione del cursore resta indefinita (l'ideale
        sarebbe che il cursore non si spostasse per nulla).

        Warning Message: "DB-API extension cursor.scroll() used"

    Cursor Attribute .messages

        Questo è un oggetto lista di Python a cui l'interfaccia
        appende le tuples (classe exception, valore exception) per tutti
        i messaggi che le interfacce ricevono dal database utilizzato
        per questo cursore. 

        La lista è pulita automaticamente da tutte le chiamate standard ai metodi su cursori
        (prima dell'esecuzione della chiamata) tranne per le chiamate
        .fetchXXX() per evitare l'uso eccessivo di memoria
        e può anche essere pulita eseguendo "del cursor.messages[:]". 

        Tutti i messaggi di warning e errore generati dal database sono
        posti in questa lista, così che il controllo della lista
        permetta all'utente di verificare la correttezza dell'operazione
        del metodo chiamato.

        Lo scopo di questa lista di attributi è di eliminare la necessita
        per una eccezione Warning che causa spesso problemi (alcuni
        warning hanno realmente spesso solo carattere informativo).

        Warning Message: "DB-API extension cursor.messages used"

    Connection Attribute .messages

        Uguale come cursor.messages a parte che i messaggi nella
        lista sono orientati alla connessione.

        La lista è pulita automaticamente da tutte le chiamate standard ai metodi su connection
        (prima dell'esecuzione della chiamata) tranne per le chiamate
        .fetchXXX() per evitare l'uso eccessivo di memoria
        e può anche essere pulita eseguendo "del connection.messages[:]". 

        Warning Message: "DB-API extension connection.messages used"

    Cursor Method .next()
 
        Ritorna la successiva colonna dallo statement sql in esecuzione
        usando la stessa semantica di .fetchone(). Una eccezione 
        StopIteration è raggiunta quando il set di risultati è terminato
        per le versioni Python 2.2 e successive. Versioni precedenti non
        hanno l'eccezione StopIteration e così il metodo deve raggiungere
        invece un errore IndexError.

        Warning Message: "DB-API extension cursor.next() used"

    Cursor Method .__iter__()

        Restituisce self per rendere i cursori compatibili con il protocollo di iterazione.

        Warning Message: "DB-API extension cursor.__iter__() used"

    Cursor Attribute .lastrowid

        Questo attributo in sola lettura fornisce il rowid della
        ultima colonna modificata (molti database ritornano un rowid
        quando una operazione di INSERT singola è eseguita).
        Se l'operazione non dovesse restituire un rowid o se il database non li supportasse
        l'attributo deve essere impostato a None.

        Le semantiche di .lastrowid sono indefinite nel caso l'ultimo
        statement eseguito ha modificato più di una riga, e.g. 
        usando INSERT con .executemany().

        Warning Message: "DB-API extension cursor.lastrowid used"

        

Estensioni alla gestione d'errore opzionali

    Il nucleo della specifica DB API introduce soltanto un
    insieme di eccezioni che possono essere sollevate per segnalare
    gli errori all'utente.  In alcuni casi, le eccezioni possono essere
    troppo distruttive per il flusso di un programma o persino rendere
    l'esecuzione impossibile. 
    
    Per questi casi e per facilitare il trattamento degli errori quando
    si lavora con database, gli autori del modulo del database possono
    scegliere di implementare gestori di eccezioni definibili dall'utente.
    Questa sezione descrive una via standard di definizione di
    questi gestori di eccezioni. 

    Cursor/Connection Attribute .errorhandler

       Attributi modificabili che riferiscono un gestore di eccezioni
       da chiamare nel caso venga incontrata una condizione d'errore.

       Il gestore di eccezioni deve essere un chiamabile Python con i
       i seguenti parametri: errorhandler(connection, cursor, errorclass, errorvalue)
       dove connection e' un riferimento alla connessione su cui il cursore opera,
       il cursor e' un riferimento al cursore (o None nel caso in cui l'eccezione non si
       riferisca ad un cursore), errorclass e' una classe d'errore da istanziare utilizzando
       errorvalue come costruttore.

       Il gestore di errori standard deve aggiungere le informazioni di
       errore all'attributo .messages adatto
       (connection.messages o cursor.messages) e sollevare l'eccezione
       definita dai dati errorclass e parametri errorvalue. 

       Se non e' definito alcune errorhandler (l'attributo e' impostato a None), la gestione
       standard degli errori deve essere applicata come indicato sopra.

       Warning Message: "DB-API extension .errorhandler used"

    I cursori debbono ereditare le impostazioni di errorhandler dagli oggetti connection
    al momento della creazione del cursore. 

Frequently Asked Questions

    Il SIG dei database vede spesso ricorrenti domande
    circa la specifica DB API.  Questa sezione copre alcune delle
    problematiche piu' comuni sulla specifica. 

    Domanda: 

       Come si puo' costruire un dizionario di tuples ottenuto
       da .fetchxxx():

    Risposta:

       Ci sono parecchi tools attualmente disponibili che forniscono
       assistenza per questa operazione. La maggior parte di loro usa
       i nomi della colonna contenuti nell'attributo
       .description del cursore come base per definire le chiavi nel dizionario.

       La ragione per non estendere le specifiche delle DB API
       e' che presenta alcuni svantaggi:

       * Alcuni database non supportano case-sensitive nomi di colonne
         o auto convertono a lowercase o uppercase tutti i caratteri.
 
       * Le colonne nel set di risultati i quali sono generati dalla
         query (e.g. utilizzando funzioni SQL) non fanno riferimento
         a colonne e i database definiscono nomi che sono specifici per ogni database.

       Come risultato, accedendo alle colonne attraverso chiavi del
       dizionario varia fra database e rende la scrittura
       di codice portabile impossibile. 


Principali modifiche dall'API v.1.0 alla v.2.0

    L'API Python per i Database v.2.0 introduce un numero limitato di cambiamenti importanti rispetto
    alla versione 1.0. Dato che alcuni di questi saranno causa di errori fatali negli script basati 
    sulla vecchia DB API 1.0, si è deciso di variare il numero di versione principale. 

    Ecco i cambiamenti più significativi dalla versione 1.0: 

        * Non è più necessario un modulo dbi separato, le sue funzionalità sono state fuse 
          nell'interfaccia di modulo. 

        * Sono stati aggiunti nuovi costruttori e oggetti Tipo per i valori di date e orari. Il tipo
          di oggetto RAW è stato rinominato come BINARY. L'insieme di tipi risultante deve 
          coprire tutti i tipi di dato fondamentali che si trovano comunemente nei moderni database SQL. 

        *  Sono state aggiunte nuove costanti (apilevel, threadlevel, paramstyle) e metodi (executemany, nextset)
        per garantire connessioni migliori ai database. 

        * Le semantiche di .callproc() necessarie a chiamare stored procedure sono ora definite chiaramente. 

        * La definizione del valore restituito da .execute() è stata cambiata. In precedenza il valore 
          restituito era basato sul tipo di operazione SQL (difficile da implementare in modo soddisfacente).
          Ora il tipo non è definito, si usi piuttosto il più flessibile attributo .rowcount. I moduli sono 
          liberi di restituire valori nel vecchio stile, ma le specifiche non se ne occupano più e debbono
          essere considerati dipendenti dalle singole interfacce [e da non utilizzarsi nell'ottica di 
          portabilità del codice NdT]. 

        * È stata incorporata nelle specifiche una gerarchia di eccezioni basata sulle classi. Gli 
          implementatori del modulo sono liberi di estendere lo schema presentato in questo documento 
          tramite sottoclassi. 

    Aggiunte alle specifiche DB API 2.0 successive alla pubblicazione:

        * Sono state inserite estensioni opzionali alle DB API.


Questioni ancora in sospeso

    Sebbene la versione 2.0 delle specifiche chiarisca molti punti che erano stati lasciati in sospeso 
    nella versione 1.0, rimangono ancora alcune questioni da affrontare: 

        Definire un valore di ritorno utile per .nextset() nel caso in cui un nuovo risultato sia 
        effettivamente disponibile. 

        Creare un tipo numerico a virgola fissa da usare come formato di scambio senza arrotondamenti 
        per valori monetari e decimali. 

Note a pie' di pagina

    [1] Come linea guida, i parametri del costruttore di Oggetti Connection debbono essere implementati
        come argomenti a parola chiave per un uso piu' intuitivo e seguire quest'ordine: 
    
        dsn = Nome della sorgente dei dati come stringa  
        user = Nome dell'utente come stringa (opzionale) 
        password = Password come stringa (opzionale 
        host = Nome dell'host (opzionale) 
        database = Nome del database (opzionale) 

        ecco un esempio di un tale uso di connect: 

        connect(dsn='myhost:MYDB',user='guido',password='234$') 

    [2] Gli autori del modulo debbono preferire i formati 'numeric', 'named' o 'pyformat'
        sugli altri, dato che offrono maggior chiarezza e flessibilità. 

    [3] Se il database non supporta la funzionalità richiesta dal metodo, l'interfaccia deve
        sollevare un'eccezione in caso venga invocato. 
        
        L'approccio preferito è non implementare il metodo, in modo che Python generi un'eccezione
        AttributeError in caso di richiesta del metodo. Ciò permette al programmatore di verificare
        quanto può offrire il database usando la funzione standard hasattr(). 
    
        Per alcune interfacce configurate dinamicamente potrebbe non essere appropriato richiedere 
        di rendere disponibile il metodo dinamicamente. Queste interfacce debbono quindi sollevare 
        un'eccezione NotSupportedError per indicare l'incapacità di eseguire il roll-back allorché il 
        metodo venisse invocato. 
    
    [4] Un'interfaccia può scegliere di supportare i cursori con nome permettendo l'aggiunta di un argomento
        stringa al metodo. Questa caratteristica non viene contemplata nelle specifiche, dato che 
        complicherebbe le semantiche dei metodi .fetchXXX(). 
    
    [5] Il modulo userà il metodo __getitem__ degli oggetti dei parametri per mappare o le posizioni 
        (interi) o i nomi (stringhe) dei valori dei parametri. Questo permette di accettare in ingresso
        sia sequenze che dizionari. 
        
        Il termine "associato" si riferisce al processo di connettere un valore in ingresso a un buffer 
        di esecuzione del database. In termini pratici questo significa che il valore in ingresso è 
        usato direttamente come valore in un'operazione. Al client non deve essere richiesto di 
        dover proteggere il valore in modo che possa essere usato, esso deve infatti essere uguale 
        al valore reale del database. 
    
    [6] Si noti che l'interfaccia potrebbe implementare il prelievo delle righe usando array e altre
        ottimizzazioni. Nulla garantisce che una chiamata a tale metodo muova il cursore associato in 
        avanti di una sola riga. 
    
    [7] L'attributo rowcount può essere codificato in modo che aggiorni dinamicamente il proprio 
        valore. Ciò può essere utile per database che restituiscono valori di rowcount 
        utilizzabili solo dopo una prima chiamata al metodo .fetchXXX(). 


Riconoscimenti

    Sentiti ringraziamenti vanno a Andrew Kuchling che ha convertito
    la specifica del Python Database API Specification 2.0
    dall'originale formato HTML nel formato dei PEP.

Copyright

    This document has been placed in the Public Domain.