Показаны сообщения с ярлыком oracle. Показать все сообщения
Показаны сообщения с ярлыком oracle. Показать все сообщения

вторник, 14 апреля 2020 г.

Oracle + PL/SQL - поиск строки в базе

Возникла тут одна небольшая задачка. Есть некая строка, например "ABC123", есть база данных на Oracle, и нужно опеределить, в каких таблицах и каких столбцах эта строка встречается. Известен владелец таблиц, назовём его HUHMUH. В общем, требуется некий reverse engineering.

К сожалению, я с ораклом дел практически не имел, поэтому не знаю всех его возможностей. Не исключено, что есть какой-нибудь штатный способ для решения этой задачи. Мне же не пришло в голову ничего умнее, чем перебрать все таблицы и все столбцы по очереди и поискать селектами строку в них.

Поскольку всё происходит под линуксом в командной строке, возникла мысль воспользоваться инструментом SQL*Plus, входящим в комплект Oracle Instant Client-а (у меня он версии 12.2). Запуск скрипта, хранящегося в файле myscript.txt, с помощью этой утилиты не представляет сложностей:
#!/bin/sh

export NLS_LANG=American_America.AL32UTF8

ora_path=/opt/oracle/instantclient_12_2

exit | $ora_path/sqlplus -S mylogin/mypassword@myserver:1521/mydatabase @myscript.txt > output.txt
Запускаем, получаем в файле output.txt всё, что этот самый скрипт посчитает нужным сообщить.

Сам скрипт тоже не содержит ничего необычного. Выглядит он так:
-- без этого не работает dbms_output
SET SERVEROUTPUT ON

-- без этого пишется лишняя строка "PL/SQL procedure successfully completed"
SET FEED OFF

DECLARE
    search_string  varchar(256);

    row_count integer;

    CURSOR cur
    IS
    SELECT
        owner,
        table_name,
        column_name
    FROM
        all_tab_columns
    WHERE
        owner = 'HUHMUH'
        and data_type like '%CHAR%'
    ORDER BY
        1, 2;

BEGIN

search_string := 'ABC123';

-- можно было сразу FOR r IN (SELECT ...) LOOP ... END LOOP;
FOR r IN cur
LOOP
    BEGIN

        EXECUTE IMMEDIATE 'SELECT count(*) FROM '
            || r.table_name
            || ' WHERE '
            || r.column_name || ' = ''' || search_string || ''' '
            INTO row_count;

        IF row_count > 0 THEN
            dbms_output.put_line(r.owner || '.' || r.table_name || ' -> ' || r.column_name);
        END IF;

    EXCEPTION
        WHEN OTHERS THEN
            dbms_output.put_line('error ' || r.owner || '.' ||r.table_name || ' -> ' || r.column_name);
            CONTINUE;
    END;

END LOOP;

END;

-- без этого не возвращается результат dbms_output
/

Вот, собственно, и всё. Работает долго, но нужные мне данные нашло.

четверг, 26 октября 2017 г.

Windows: установка Oracle Instant Client

Понадобилось тут прицепиться из-под Windows 2003 к базе на Oracle 11g, если не ошибаюсь. Гугль вывел на страницу загрузки разных вариантов Oracle Instant Client.

Под линуксом всё оказалось просто: скачал нужный архив, распаковал из него папку instantclient_12_2, в строгом соответствии с инструкциями сделал пару линков на нужные библиотеки, прописал в /etc/ld.so.conf полный путь этого самого instantclient_12_2 и вызвал ldconfig. Всё. SQL*Plus сразу начал цепляться куда надо, и осталась одна проблема: Python 2.7 через cx_Oracle не сразу понял русские буквы, и потребовалось добавить в начало скрипта конструкцию:
import os
os.environ["NLS_LANG"] = "American_America.AL32UTF8"
А для SQL*Plus не потребовалось и этого.

Иное дело Windows 2003. Под ним я тоже распаковал instantclient_12_2, в эту же папку сгрузил файлы из архивов для ODBC и SQL*Plus, добавил её полный путь в системную переменную окружения PATH и попытался создать системный DSN. Безуспешно. На экран вывалились одна за одной ошибки "Не удается загрузить программы установки для драйвера ODBC Oracle in instantclient_12_2 из-за системной ошибки с кодом 127" и "Не удается загрузить программу установки или библиотеку транслятора", и начался квест, закончившийся полным провалом. Ставлю Microsoft Visual Studio 2013 Redistributable - не помогает. Нахожу замечательную утилиту Dependency Walker 2.2, которая, по аналогии с линуксовой ldd показывает зависимости библиотек, натравливаю её на sqora32.dll и sqoras32.dll, выясняется, что этим библиотекам для счастья нужны mfc110.dll и msvcr110.dll, нахожу их в установленных каких-то левых программах, копирую в instantclient_12_2 - всё без толку. Мало того, даже sqlplus.exe запускаться не желает. Может, в оракле перепутали 32-х и 64-х битную версии?

Разбираться не стал. Снёс Instant Client 12.2, поставил Instant Client 11.2. Тому тоже не хватает библиотек, на этот раз mfc80.dll и msvcr80.dll. Их найти легче, у меня они валялись в установленном клиенте SQL Server 2005. Подпихнул их в папку instantclient_11_2, окно настройки свойств подключения появилось.

Но на этом приключения не закончились. Как известно, описания оракловских подключений хранятся в файле tnsnames.ora, путь к папке которого по идее должен быть указан в переменной окружения TNS_ADMIN. Описываю своё подключение, выбираю его в окне настройки свойств "Oracle ODBC Driver Configuration" в поле TNS Sеrvice Name, пытаюсь сделать проверку подключения - получаю ошибку "ORA-12154 TNS:could not resolve the connect identifier specified". Пришлось схитрить: в поле TNS Sеrvice Name прописать подключение в формате host:port/service_name.

Ладно, так или иначе, подключился. Опять возникла проблема с русскими буквами. Причем на ровном месте. В SQL*Plus выдаётся всё хорошо, запрос
select * from v$nls_parameters where parameter like '%CHARACTERSET%';
показывает обнадёживающее "CL8MSWIN1251", то есть, никакая перекодировка не нужна, но простейший ASP-скрипт в кодировке cp1251:
Dim Conn
Set Conn = Server.CreateObject("ADODB.Connection")

Conn.Open "Provider=MSDASQL.1;Password=***;Persist Security Info=True;User ID=huh-muh;Data Source=MYORA"

Set RS = Server.CreateObject("ADODB.Recordset")
strSQL = "select 'привет' from dual"

RS.Open strSQL, Conn

RS.MoveFirst
Response.Write RS.Fields(0)

RS.Close
Set RS = Nothing

Conn.Close
Set Conn = Nothing
вместо обнадёживающего "привет" рисует на странице удручающие знаки вопроса: "??????". Оказывается, надо прописать параметр NLS_LANG=RUSSIAN_CIS.CL8MSWIN1251, но где это сделать, совершенно непонятно. В конце концов, пристроил этот параметр в реестр:
[HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]
"NLS_LANG"="RUSSIAN_CIS.CL8MSWIN1251"
Правда, после этого неожиданно русифицировались SQL*Plus и сообщения оракла об ошибках, но и чёрт с ними. Главное, ASP-скрипты перестали глючить.

пятница, 8 января 2010 г.

Настройка Oracle instant client

1. Ему зачем-то нужны файлы tnsnames.ora (ну, это еще понятно) и sqlnet.ora. При этом ищет он их в директории, указанной в переменной среды TNS_ADMIN. Попытка прописать данную директорию в виде строкового параметра в реестр (HKLM\SOFTWARE\ORACLE\) успехом не увенчалась. Ладно, пусть будет переменная среды.

2. Для правильного отображения русских букв под виндой понадобился строковый параметр HKLM\SOFTWARE\ORACLE\NLS_LANG = RUSSIAN_CIS.CL8MSWIN1251