Nano Hash - криптовалюты, майнинг, программирование

Oracle For Loop в хранимой процедуре не зацикливается

Пытаясь улучшить ремонтопригодность SP в одной из наших систем, я решил, что использование цикла будет лучше, чем жестко закодированный массив значений (в данном случае имен таблиц), и попытался соответствующим образом реорганизовать код, чтобы добавление или удаление таблицы в систему не требовало редактирования массива. Оставив пока в стороне вопросы почему и зачем циклы (я очень хорошо знаю аргументы против них), может ли кто-нибудь объяснить, что происходит?

Представьте себе двух пользователей, SourceUser и DestUser, обоих в одной базе данных, каждый со своими таблицами в одном и том же табличном пространстве. Куча хранимых процедур в SourceUser заполняет данные из SourceUser в DestUser для целей отчетности. В рамках этого первая запускаемая процедура удаляет все таблицы в DestUser и создает их заново. Опять же, не обсуждая относительные достоинства этого здесь.

SourceUser имеет права Drop Any Table и Create Any Table на DestUser. В DestUser есть одна таблица, которую мы хотим сохранить. Итак, SQL, который я построил в процедуре, выглядит так:

Begin
  For T In (SELECT TABLE_NAME FROM all_tables WHERE TABLE_NAME != 'MIDBLOG' AND OWNER = sTarget_DB) Loop
    Begin
      Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);

    Exception
      When Others Then
        --Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
        NULL;
    End;
  End Loop;
End;

В этом случае для sTarget_DB установлено значение DestUser, и этот код запускается для SourceUser.

Когда процедура запускается, я обнаруживаю, что никакие таблицы не были удалены (перед запуском я убедился, что было несколько десятков таблиц, включая одну с именем MIDBLOG). Я запустил его в режиме отладки SQL Developer, и выполнение даже не попало внутрь цикла, поскольку кажется, что у него нет строк для обработки, но я точно знаю, что оператор select вернет пару десятков имен таблиц.

Далее я изменил его на это:

Begin
  For T In (SELECT TABLE_NAME FROM all_tables WHERE OWNER = sTarget_DB) Loop
    Begin
      If T.TABLE_NAME != 'MIDBLOG' THEN
        Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);
      End If;
    Exception
      When Others Then
        --Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
        NULL;
    End;
  End Loop;
End;

После этого единственная таблица, которую БЫЛО удалено, была той самой, которую я не хотел удалять! Еще более странным было то, что цикл выполнялся только один раз, как будто запрос на выборку возвращал только одну строку. Я мог бы увидеть, как это происходит, если бы я запускал процедуру в режиме отладки в SQL Developer 3.2. Мы сделали то же самое на ПК коллеги на SQL Developer (возможно, 3.1), и снова цикл выполнился только один раз, но на этот раз он правильно решил не удалять таблицу MIDBLOG и снова оставил все остальное в покое.

Если я запускаю любой из приведенных выше примеров как анонимный блок в SQL Developer, он делает именно то, что я ожидаю. Я попробовал более подробное явное объявление курсора и получил те же результаты, что и раньше. Я ни разу не получил никаких исключений.

Все это было на Oracle 10g Enterprise Edition Release 10.2.0.4.0 (64bit). Как только я попробовал это на Oracle 11g Enterprise Edition Release 11.2.0.1.0 (64-разрядная версия), все заработало нормально. С какой стати такое базовое требование должно демонстрировать такое сильно различное поведение в двух версиях? Может ли это работать так, как я хочу, в обеих версиях с одним и тем же кодом?


  • Что касается исключения others и сопровождающего его комментария - есть несколько причин, по которым команда drop table может завершиться ошибкой, кроме отсутствия таблицы. Было бы лучше явно обработать исключение -942 и позволить остальным ошибаться должным образом. 24.04.2016
  • Это правда, но фактическое исключение, насколько я помню, не представляло интереса в рассматриваемом сценарии - это было 3 1/2 года назад! 24.04.2016

Ответы:


1

Я предполагаю, что проблема связана с привилегиями, а не с версией Oracle. Предоставляются ли привилегии на DestUser SrcUser через роль в одной базе данных и через прямые гранты в другой?

Что произойдет, если сначала отключить роли перед запуском анонимного блока PL/SQL?

set role none;
<<run the anonymous PL/SQL block>>

Если вы добавите инструментарий в код, вернет ли запрос к all_tables набор таблиц, который вы ожидаете? Я предполагаю, что когда код дает сбой, это происходит в хранимой процедуре прав определителя, где владелец процедуры имеет доступ к DestUser таблицам через роль. Поскольку привилегии, предоставленные через роль, не видны в хранимой процедуре прав определителя, это приведет к тому, что оператор SELECT в вашем цикле вернет 0 строк (хотя выполнение того же запроса в интерактивном режиме вернет ожидаемые строки). С другой стороны, если привилегии для таблиц DestUser предоставляются напрямую, то хранимая процедура прав того же определителя будет успешно выполнена. И это будет работать в анонимном блоке PL/SQL.

29.11.2012
  • Я проверю любые роли и т. д., но во всех случаях гранты предоставляются напрямую, а не по ролям. Что меня озадачивает, так это то, почему один человек получает 0 строк, а другой получает 1 строку на сервере 10g. Оба используют один и тот же логин и, следовательно, имеют одинаковые привилегии. Я попробую отключить роли и отчитаюсь. Запрос к all_tables возвращает именно то, что я ожидаю отдельно, поэтому я не понимаю, как он может различаться между компьютерами и серверами. 30.11.2012
  • ОК, как вы предложили, я попытался отключить все роли перед запуском анонимного блока на обоих серверах, и, конечно же, результат тот же, что и вы предложили: установить роли none => анонимный блок ничего не делает, и запуск select сам по себе не дает никаких результатов. Результаты. Я вынужден сделать вывод, что у нас есть несоответствие в нашей настройке между двумя серверами, поэтому, если я хочу продолжать с этим, мне нужно исследовать, как у нас есть роли, работающие на наших (и наших клиентских) серверах. Позор, гораздо более аккуратное решение, чем массив имен таблиц! 30.11.2012
  • Из-за давления графиков разработки это должно быть продолжено в академической части, но, что вызывает тревогу, нашим пользователям (SourceUser и DestUser) предоставляется роль DBA, которая, как я думал, будет достаточной, но, возможно, SP выполняются под управлением какой-то другой системы. Пользователь. Не будучи администратором баз данных Oracle, я немного запутался в этом вопросе, но продолжу читать об этом. Однако большое спасибо за вашу помощь. 30.11.2012
  • @StevePettifer - Предоставление любому пользователю роли DBA - плохая идея с точки зрения безопасности. Поскольку все роли невидимы в хранимой процедуре прав определяющего, хранимая процедура прав определяющего не может использовать привилегии, предоставленные роли DBA или любой другой роли. Он может использовать только те привилегии, которые предоставлены непосредственно пользователю. 30.11.2012
  • Я полностью согласен - когда я обнаружил это, я был удивлен и более чем обеспокоен. В качестве дополнения я обнаружил, что добавление authid current_user к объявлению SP сортирует проблемы и гарантирует, что хранимая процедура наследует правильное разрешение для достижения того, что я хотел. Цель и теория этого были хорошо объяснены здесь: docs .oracle.com/cd/B19306_01/appdev.102/b14261/ 30.11.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..