2016-05-19 33 views
5

Uno dei compiti di OJDBC consiste nel mappare i tipi di dati Oracle in tipi Java.Perché OJDBC 7 non associa il tipo di dati CHAR a una stringa Java?

Tuttavia, abbiamo notato che se diamo un tipo di dati CHAR, non è mappato a java.lang.String. Le versioni che mostrano questo comportamento sono: OJDBC7 v12.1.0.2 e OJDBC6 v12.1.0.1. Le versioni precedenti effettivamente mappavano il tipo di dati CHAR a: java.lang.String.

a scavare più a fondo, abbiamo scoperto che c'è una classe: StructMetaData all'interno del pacchetto di OJDBC oracle.jdbc.driver che implementa il tipo di dati Oracle per Java Tipo mappatura. C'è un metodo al suo interno: 'getColumnClassName (int arg0)' che è degno di attenzione. Abbiamo notato che per OJDBC v7, i casi mappati java.lang.String sono i seguenti:

int arg1 = this.getColumnType(arg0); 
    switch (arg1) { 
    case -104: 
     return "oracle.sql.INTERVALDS"; 
    case -103: 
     return "oracle.sql.INTERVALYM"; 
    case -102: 
     return "oracle.sql.TIMESTAMPLTZ"; 
    case -101: 
     return "oracle.sql.TIMESTAMPTZ"; 
    case -15: 
    case -9: 
    case 12: 
     return "java.lang.String"; 
    ... 

Tuttavia, all'interno di implementazioni OJDBC più anziani, che si presentava così:

int arg1 = this.getColumnType(arg0); 
    switch (arg1) { 
    case -104: 
     return "oracle.sql.INTERVALDS"; 
    case -103: 
     return "oracle.sql.INTERVALYM"; 
    case -102: 
     return "oracle.sql.TIMESTAMPLTZ"; 
    case -101: 
     return "oracle.sql.TIMESTAMPTZ"; 
    case -15: 
    case -9: 
    case 1: 
    case 12: 
     return "java.lang.String"; 
    ... 

V'è un ulteriore caso mappato java.lang.String in quest'ultimo caso vale a dire 'caso 1'. Questo 'caso 1' non è mappato a java.lang.String nel primo frammento di codice mostrato sopra.

Guardando più profondo, questo 'caso 1' viene mappata CHAR all'interno del metodo getColumnTypeName(int arg0) della stessa classe StructMetaData:

public String getColumnTypeName(int arg0) throws SQLException { 
    int arg1 = this.getColumnType(arg0); 
    int arg2 = this.getValidColumnIndex(arg0); 
    switch (arg1) { 
    case -104: 
     return "INTERVALDS"; 
    case -103: 
     return "INTERVALYM"; 
    case -102: 
     return "TIMESTAMP WITH LOCAL TIME ZONE"; 
    case -101: 
     return "TIMESTAMP WITH TIME ZONE"; 
    case -15: 
     return "NCHAR"; 
    case -13: 
     return "BFILE"; 
    case -9: 
     return "NVARCHAR"; 
    case -2: 
     return "RAW"; 
    case 1: 
     return "CHAR"; 
... 

Per questo motivo, se usiamo OJDBC 7 o OJDBC6 v12.1.0.1 e specificare CHAR come tipo di dati per una colonna, il seguente codice restituisce null su invocazione per l'indice di questa colonna:

for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { 
    ... 
    resultSetMetaData.getColumnClassName(columnIndex) 
    ... 

Se sostituisco una versione precedente del vaso OJDBC (ad esempio: 11.2.0.3), quindi restituisce lo stesso codice: java.lang.String. È un bug o è stato rimosso dalla progettazione? Qualcuno ha affrontato lo stesso problema in precedenza?

+1

Avete controllato le note di rilascio del driver? Se ritieni che ciò sia sbagliato, apri una SR con My Oracle Support. Sono rimasto molto contento delle soluzioni offerte. –

risposta

0

Buona presa ...!

Sembra davvero un bug; forse l'unica argomentazione contro è che sarebbe incredibilmente enorme trascurare da Oracle.

Pro bug:

  • all'indietro problema di compatibilità.Gli aggiornamenti del driver JDBC interromperebbero le applicazioni esistenti che sono esplicitamente basandosi sulla CHAR dichiarazione
  • Questa nota su JPublisher Data Type and Java-to-Java Type Mappings descrive la mappatura come di 12c

(notare la prima fila, in relazione al tipo di CHAR, che mappe per java.lang.String)

| SQL and PL/SQL Data Type | Oracle Mapping | JDBC Mapping 
|------------------------- |------------------|----------------------------------------------- 
| CHAR, CHARACTER, LONG, |     | 
|STRING, VARCHAR, VARCHAR2 | oracle.sql.CHAR | java.lang.String 
| NCHAR, NVARCHAR2   | oracle.sql.NCHAR | oracle.sql.NString 
| NCLOB     | oracle.sql.NCLOB | oracle.sql.NCLOB 

contro bug:

  • Un'ipotesi di fantasia potrebbe sostenere che Oracle sta cercando di eliminare CHAR s dai tipi supportati. Infatti, il tipo CHAR non ha davvero alcun vantaggio rispetto allo VARCHAR2, e alcuni aspetti negativi lo rendono una scelta irrinunciabile. In passato mi è piaciuto il fatto che un "CHAR" comunichi agli altri sviluppatori la tua intenzione di definire un oggetto con una lunghezza predefinita e invariabilmente fissa, ma non lo applica nemmeno (basta riempire la stringa, se la si riempie con anche un valore breve). Se sei interessato, c'è una sezione nell'eccellente libro Expert Oracle Database Architecture - Oracle Database 9i, 10g, and | Thomas Kyte | Apress dedicato all'argomento. Si può leggere un estratto in Ask Tom "Char Vs Varchar", nel punto in cui l'autore cita il suo libro:

Il fatto che un car/NCHAR è davvero niente di più che un VARCHAR2/NVARCHAR2 sotto mentite spoglie mi fa del parere ci sono davvero solo due tipi di stringhe di caratteri da prendere in considerazione, vale a dire VARCHAR2 e NVARCHAR2. Non ho mai trovato un utilizzo per il tipo CHAR in qualsiasi applicazione. Dal momento che un tipo CHAR sempre vuoto riempie la stringa risultante fino a una larghezza fissa, scopriamo rapidamente che consuma la massima memorizzazione sia nel segmento della tabella sia in qualsiasi segmento dell'indice. Sarebbe già abbastanza grave, ma c'è un altro motivo importante per evitare i tipi CHAR/NCHAR: creano confusione nelle applicazioni che hanno bisogno di recuperare queste informazioni (molti non possono "trovare" i loro dati dopo averli memorizzati). La ragione di ciò si riferisce alle regole del confronto delle stringhe di caratteri e alla severità con cui vengono eseguite. ....

[quindi un grande esempio segue nello stesso post; vale la pena leggerlo]

Il fatto che lo CHAR non sia valido, ovviamente, non giustifica Oracle dalla violazione delle applicazioni esistenti senza preavviso; quindi l'ipotesi che sia un bug è chiaramente più sensata.

Dato che teoricamente non avrebbe svantaggi, come soluzione estrema potresti alterare tutte le tabelle coinvolte per ridefinire i loro tipi CHAR come VARCHAR2 (se hai il diritto di farlo, ed è fattibile).