Вставка CLOB в базу данных, выбранную из другого

У меня есть два несвязанных экземпляра базы данных oracle 11g. Мне нужно выбрать значение типа CLOB из одной базы данных и вставить его в другую с помощью python, используя cx_Oracle.

Когда я пытаюсь это сделать в одном направлении, это заканчивается:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist

Как ни странно, при попытке в другом направлении это заканчивается:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: internal error code, arguments: [kglslod:subheap], [8], [0x14D9EA270], [], [], [], [], [], [], [], [], []

Выбор и вставка значения CLOB в одной и той же базе данных не проблема.

Я обнаружил, что могу исправить это с помощью специального обработчика вывода:

def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
    if defaultType == cx_Oracle.CLOB:
        return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)

и настройка

db_connection.outputtypehandler = OutputTypeHandler

Поэтому мне интересно, такое поведение по дизайну или что еще приводит к этому?


Вот некоторые данные для тестирования:

Создайте таблицу и вставьте строку в базу данных1

create table test_table_1
(
    column_1 clob
);

insert into test_table_1 (column_1) values ('test_data_1');

Создайте таблицу и вставьте строку в базу данных2

create table test_table_2
(
    column_2 clob
);

insert into test_table_2 (column_2) values ('test_data_2');

Скрипт Python, который не смог получить один результат из базы данных1 и вставить его в базу данных2

import cx_Oracle


db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()

cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])

Результат

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: Interner Fehlercode, Argumente: [kglslod:subheap], [8], [0x14DF5A0B0], [], [], [], [], [], [], [], [], []

Результат при выборе из базы данных2 и вставке в базу данных1

Traceback (most recent call last):
  File "<input>", line 8, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist

Скрипт Python, который работает

import cx_Oracle

def OutputTypeHandler(cursor: cx_Oracle.Cursor, name, defaultType, size, precision, scale):
    """
    Convertes CLOB type to string on reading.
    """
    if defaultType == cx_Oracle.CLOB:
        return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)

db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_1.outputtypehandler = OutputTypeHandler
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()

cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])

db_2.commit()

Версии

  • cx-Оракул 7.2.0
  • oracle_instant_client 18.5 (Линукс)
  • питон 3.6.8

Можете ли вы поделиться полностью работоспособным тестовым примером, демонстрирующим проблему, чтобы нам не приходилось строить догадки? Убедитесь, что вы используете последнюю версию cx_Oracle. Последняя версия 7.2.

Christopher Jones 24.07.2019 13:03

Я добавил тестовый пример.

finswimmer 24.07.2019 13:34
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
245
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете просто передать значение LOB из одного соединения в другое. Они специфичны для конкретного соединения. Я постараюсь предоставить лучшее сообщение об ошибке для этой ситуации.

Как вы отметили в своем собственном вопросе, первое решение - использовать STRING вместо CLOB с помощью обработчика типа вывода. Этот метод работает со значениями CLOB размером до 1 ГБ, но недостатком является то, что все значение CLOB должно находиться в непрерывной памяти.

Если вам нужно передать значения из-за очень большой длины, вам нужно будет использовать что-то вроде этого:

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

cursor_1.execute("select column_1 from test_table_1")
sourceLob, = cursor_1.fetchone()

lobVar = cursor_2.var(cx_Oracle.CLOB)
cursor_2.execute("insert into test_table_2 (column_2) values (empty_clob()) returning column_2 into :1", [lobVar])
destLob = lobVar.getvalue()

offset = 1
numBytesInChunk = 65536
while True:
    data = sourceLob.read(offset, numBytesInChunk)
    if data:
        destLob.write(data, offset)
    if len(data) < numBytesInChunk:
        break
    offset += len(data)
db_2.commit()

Это то, что я имел в виду под «это по замыслу?». Это потому, что оракул просто хранит ссылку на хранилище clob в таблице? Лучшее сообщение об ошибке было бы действительно хорошо. :) Мне потребовались часы, чтобы найти проблему.

finswimmer 24.07.2019 19:55

Библиотеки Oracle Client не поддерживают эту концепцию, поэтому я думаю, вы можете подумать, что это «по задумке». :-)

Anthony Tuininga 25.07.2019 00:17

Другие вопросы по теме