Java Исправлена ​​проблема с символами, но вы хотите понять, как сгенерированы неправильные данные - PullRequest
1 голос
/ 10 января 2020

Попытка вставить такую ​​строку в таблицу Oracle: ABčDE

Таблица Oracle определяется следующим образом:

SQL> create table DUMMY_TEST (Field1 number, Name_Test varchar2(20));

Ниже приводится Java / JDB C код используется. Это делает 2 вставки. Одна вставка жестко запрограммирована в коде, а вторая извлечена из файла.

import java.sql.*;
import java.util.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Locale;


class JdbcTest
{
    static StringBuffer sbuff = new StringBuffer();

    public static void main (String a[])
    {
        //Creating the connection
        String url = "jdbc:oracle:thin:@//server:port/ServiceName";
        String user = "xa21appdb";
        String pass = "neptune";

        //Inserting data using SQL query
        String sql = "INSERT INTO DUMMY_TEST VALUES(1, 'ABèDE')";

        loadDataFromFile();

        Connection con=null;
        try
        {
            DriverManager.registerDriver(new oracle.jdbc.OracleDriver());

            //Reference to connection interface
            con = DriverManager.getConnection(url,user,pass);

            Statement st = con.createStatement();
            System.out.println("Executing 1st INSERT");
            int m = st.executeUpdate(sql);
            if (m == 1)
                System.out.println("1st inserted successfully ");
            else
                System.out.println("1st insertion failed");

            System.out.println("Executing 2nd INSERT");
            m = st.executeUpdate(sbuff.toString());
            if (m == 1)
                System.out.println("2nd inserted successfully ");
            else
                System.out.println("2nd insertion failed");

            con.close();
        }
        catch(Exception ex)
        {
            System.err.println(ex);
        }
    }

    static void loadDataFromFile()
    {
        try
        {
            InputStream inputStream = new FileInputStream("/tmp/input.txt");
         Reader      inputStreamReader = new InputStreamReader( inputStream, "UTF-8");

            int ch = inputStreamReader.read();

            while(ch != -1)
            {
                sbuff.append((char) ch);
                ch = inputStreamReader.read();
            }
            inputStreamReader.close();
        }
        catch(Exception e){}
    }
}

Здесь находится содержимое файла, которое содержит то же SQL, что и жестко закодированное значение.

> cat /tmp/input.txt
INSERT INTO DUMMY_TEST VALUES(2, 'ABèDE')

Чтобы жестко закодировать SQL и SQL из файла, команда xxd использовалась для отображения шестнадцатеричных значений.

Показывает только оператор INSERT и строку ABčDE для вставки.

> xxd -b JdbcTest.java
    :
    :
000019e: 01101100 00100000 00111101 00100000 00100010 01001001  l = "I
00001a4: 01001110 01010011 01000101 01010010 01010100 00100000  NSERT
00001aa: 01001001 01001110 01010100 01001111 00100000 01000100  INTO D
00001b0: 01010101 01001101 01001101 01011001 01011111 01010100  UMMY_T
00001b6: 01000101 01010011 01010100 00100000 01010110 01000001  EST VA
00001bc: 01001100 01010101 01000101 01010011 00101000 00110001  LUES(1
00001c2: 00101100 00100000 00100111 01000001 01000010 11101000  , 'AB.
00001c8: 01000100 01000101 00100111 00101001 00100010 00111011  DE')";

Показывает весь код файла, который читается со вставляемой строкой ABčDE.

> xxd -b /tmp/input.txt
0000000: 01001001 01001110 01010011 01000101 01010010 01010100  INSERT
0000006: 00100000 01001001 01001110 01010100 01001111 00100000   INTO
000000c: 01000100 01010101 01001101 01001101 01011001 01011111  DUMMY_
0000012: 01010100 01000101 01010011 01010100 00100000 01010110  TEST V
0000018: 01000001 01001100 01010101 01000101 01010011 00101000  ALUES(
000001e: 00110010 00101100 00100000 00100111 01000001 01000010  2, 'AB
0000024: 11101000 01000100 01000101 00100111 00101001 00001010  .DE').  

При сравнении файла 2 он подтверждает, что строка идентична жесткому коду и файлу.

00100111 01000001 01000010 11101000 01000100 01000101 00100111
   '        A         B       .        D        E         '

Когда код запускается, следующие 2 строки вставляются в Oracle.

SQL> select * from dummy_test;

    FIELD1 NAME_TEST
---------- --------------------
         1 ABèDE
         2 AB?DE

Использование команды DUMP для получения сведений для каждого.

SQL> select field1,  dump(name_test, 1016) from dummy_test;

    FIELD1   DUMP(NAME_TEST,1016)
----------   -------------------------------------------------------------
         1   Typ=1 Len=6 CharacterSet=AL32UTF8: 41,42,c4,8d,44,45
         2   Typ=1 Len=7 CharacterSet=AL32UTF8: 41,42,ef,bf,bd,44,45

Если код изменен с этого:

Reader      inputStreamReader = new InputStreamReader( inputStream, "UTF-8");

на это:

Reader      inputStreamReader = new InputStreamReader( inputStream);

Это работает, так как обе строки покажут следующее:

SQL> select field1,  dump(name_test, 1016) from dummy_test;

    FIELD1   DUMP(NAME_TEST,1016)
----------   -------------------------------------------------------------
         1   Typ=1 Len=6 CharacterSet=AL32UTF8: 41,42,c4,8d,44,45
         2   Typ=1 Len=6 CharacterSet=AL32UTF8: 41,42,c4,8d,44,45

Теперь на 3 вопроса.

1 - В сценарии, когда он работает и «специальный» символ вставлен правильно, это можно подтвердить, поскольку набор символов Oracle AL32UTF8 показывает, что c4 8d представляет č, но мой вопрос заключается в том, почему Oracle распечатка è.

2 - Когда UTF-8 используется с READER, вставляются 3 байта (ef, bf, bd). Если я правильно выполнил вычисления в UTF-8, то получилось что-то вроде следующего:

‭11101111‬  ‭10111111‬  ‭10111101‬
1111‬111111‬111101‬
FF FD

И это очень необычный персонаж.

Хотя я понимаю, что произошел конфликт с преобразованием, но не могли бы вы объяснить, что именно произошло?

Отредактировано, чтобы добавить третий вопрос.

3 - Сессия My Putty содержит набор символов: ISO-8859-1: 1998 (Latin-1, Западная Европа) Почему в командной строке отображается ABèDE вместо ABčDE?

...