Home

Advertisement

Previous Entry | Next Entry

Описание модуля cx_Oracle

  • Aug. 19th, 2008 at 3:26 PM

Python - глазами DBA

(Описание модуля cx_Oracle)

boomzoomer-comp
http://boomzoomer-comp.livejournal.com  2003-2007 г.


Содержание


Почему собственно python


Администраторы БД очень часто нуждаются в инструментах для автоматизации разной рутинной работы, например: загрузка, преобразования данных в разного рода форматы или сбор и анализ различной статистики.Для меня в свое время такой палочкой-выручалочкой стал perl.

Через некоторое время я набрел на python.Вот все что я могу сказать после 1 года знакомства:
Это практичный и полезный инструмент.

Несколько слов об инструментах.Вариантов на самом деле немного: 1)гремучая смесь из разных утилит командной строки (bash+awk+tar+...), 2)языки сценариев(perl,tcl/tk... ), 3)классические языки программирования(С,C++)

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

Третий вариант позволяет получить великолепное решение при значительных затратах сил и времени на программирование,отладку и тестирование кода.А если их нет?

Золотой серединой очевидно является вариант номер 2.

К языкам сценариев по функциональным возможностям приближается java, поскольку фирма Oracle(к моему большому сожалению )взяла главный курс на использование языка java везде,где это только возможно, теперь java работает в контексте ядра Oracle и в принципе может быть использована как инструмент администратора.

Проблемы я вижу следующие:
-слишком сложные API,плохая читабельность кода
-отсутствие встроенных современных типов данных,
- крайняя медлительность выполнения,
-необходимость обновлять программы с Oracle Metalink.
- Java API имеет плохую обратную совместимость с предыдущими версиями
-java -это не собственная разработка Oracle corp., а технология , лицензированная у Sun , которая кое-что лицензировала еще у нескольких фирм.


С perl обычно все намного лучше.Дух открытости (движение Open Source и лицензия GPL) позволил Perl прогрессировать с космической скоростью:
-огромное количество великолепных библиотек,
-встроенные структуры данных-списки,hash-таблицы
-существование многочисленных книг, списков рассылки и просто энтузиастов значительно облегчают жизнь профессионалу.

Несмотря на массу положительных свойств, Perl имеет imho ряд существенных недостатков:
-крайне запутанный и к тому же подверженный изменениям синтаксис.
-значительная интеграция с юниксообразными ОС.
-не очень удачные средства поддержки OOP

Первое затрудняет сопровождение (даже собственных) программ.А второе ограничивает сферу применимости языка на других платформах.

И здесь важно отметить, что разработчики python в значительной степени учли достоинства и недостатки различных языков программирования и в результате появился язык программирования, который почти не содержит в себе экзотических конструкций и позволяет использовать почти все известные на сегодня методы создания программ.

Справедливости ради нужно заметить, что python отнюдь не является чем то  уникальным, мне известен еще один язык программирования с похожим функционалом - ruby.Этот язык несколько моложе чем python и для серьезного промышленного применения он еще, похоже не готов.Не все в порядке с документацией и набор библиотек совсем невелик. Ruby довольно популярен среди американских студентов, поэтому, возможно у него впереди  яркая судьба.

Достоинства языка python

Python можно охарактеризовать в нескольких словах следующим образом:
многоплатформенный язык сценариев с динамической типизацией,встроенными структурами данных и поддержкой трех парадигм программирования-процедурной,объектной, функциональной.

  • Многоплатформенность и масштабируемость-работает на большинстве известных программно-аппаратных платформ от PDA до CRAY и IBM 390
  • Гармоничная архитектура языка:
    • Простой и удобный для понимания логики програм синтаксис
    • Встроенные структуры данных-списки, кортежи,словари
    • Огромное количество библиотек:
      -XML парсеры
      -GUI(Win32,GTK/GNOME,KDE/QT,TK,FOX,WXWindows)
      - Сетевые протоколы
      - Разработка Web приложений
    • Переносимость кода между различными платформами
    • Мощные интерфейсы к конкретным ОС(особенно к Linux/Unix и win32)
    • Поддержка разных стилей программирования-процедурного,объектного,функционального
    • Встроенная поддержка Unicode и множества национальных кодировок
      (включая 5 русских)
    • Возможность писать самодокументированные программы и автоматическая генерация документации на модули.

С чем реально сталкивается программист(а админитстратор является таковым часто, но понемногу ) при использовании python.Это простой и ясный синтаксис. Я ловлю себя часто на мысли,что просмотр чужого кода зачастую не требует значительного напряжения.И здесь помогает то, что отступы являются частью синтаксиса и определяют вложенность операторов.

Библиотеки зачастую имеют очень лаконичную документацию, но этого достаточно так как API очень выразительны и внятны. Отрадным явлением в мире питона, является тот факт, что очень многие библиотеки были разработаны после того, как были согласованы спецификации на конкретные API.Одной из таких спецификаций является спецификация на Python Database API 2.0. В соответствии с этой спецификацией разрабатываются модули для доступа к конкретным СУБД.

К сожалению сам стандарт(как в свое время и cпецификация на ODBC) не может учесть все специфические особенности конкретной СУБД, так как фирмы-производители СУБД, используют свои фирменные расширения как средство в конкуретной борьбе. Поэтому перенос кода с одной платформы на другую все-таки очень трудно сделать безболезненным, если только перед разработчиками не ставилась задача писать приложения, предназначенное для работы с различными SQL серверами.

Сам процес кодирования и тестирования достаточно комфортен.Здесь помогает качественная диагностика ошибок.Оттестированные модули очень легко расширять и складывать из них приложения.

Для работы с RDBMS Oracle существует несколько различных модулей для Python, использующих разные механизмы:

  • ODBC(Win32,Linux)
  • DCOM(Win32)
  • PERL_DBI(Win32,Linux,Solaris,HP-UX,AIX)
  • NATIVE API (Win32,Linux,Solaris,HP-UX,AIX)

Более подробную информацию Вы можете найти на www.python.org.


Часть I. Выполняем простой запрос.


Я предпочитаю использовать модуль cx_Oracle, который был проверен мною в ОС NT и Linux(автор-Anthony Tuininga утверждает что он работает в Solaris и похоже, на всех юниксообразных ОС должен также работать ).В основном этот модуль следует спецификации Python Database API 2.0 и поддерживает работу с RDBMS Oracle версий 8.1-9.xx.

Модуль написан на языке С, что обеспечивает быструю обработку данных и позволяет использовать все достоинства языка Python.

Для быстрого погружения в предмет я приведу фрагменты кода, демонстрирующего основные приемы использования модуля.

try:
    import cx_Oracle
except ImportError,info:
    print "Import Error:",info
    sys.exit()
if cx_Oracle.version<'3.0':
    print "Very old version of cx_Oracle :",cx_Oracle.version
    sys.exit()
	

В этом фрагменте демонстрируется безопасная загрузка модуля cx_Oracle и проверка версии. Надеюсь, элегантность синтаксиса все-таки заметили :-)

Далее создадим экземпляр класса connect, именно этот объект и обеспечивает взаимодействие с сервером Oracle

try:
    my_connection=cx_Oracle.connect('system/manager@test_db')
except cx_Oracle.DatabaseError,info:
    print "Logon  Error:",info
    exit(0)

Теперь создаем курсор и выполняем запрос:

    
my_cursor=my_connection.cursor()
try:
    my_cursor.execute("""
    SELECT OWNER,SEGMENT_TYPE,TABLESPACE_NAME,SUM(BLOCKS)SIZE_BLOCKS,
    COUNT(*) SIZE_EXTENTS FROM DBA_EXTENTS
    GROUP BY OWNER,SEGMENT_TYPE,TABLESPACE_NAME
    """)
except cx_Oracle.DatabaseError,info:
    print "SQL Error:",info
    exit(0)

Динамическая типизация и поддержка сложных структур данных позволяет легко обработать результаты SQL запроса. В результате вызова my_cursor.fetchall() возращается список записей,каждая из которых явлеяется кортежем(неизменяемым списком) полей разного типа. Если вы знакомы с PL/SQL, то тогда цикл по списку записей будет очевидным:


for record in my_cursor.fetchall():	<обработка записи record,	
record содержит кортеж из полей текущей записи>

Существует еще более любопытная возможность "разобрать" текущую запись по полям:

for OWNER,SEGMENT_TYPE,TABLESPACE_NAME,SIZE_BLOCKS,SIZE_EXTENTS in my_cursor.fetchall():	
<теперь можно обращаться к переменным, 
содержащим значения одноименных полей курсора>

Печатаем результат на stdout. Замечу здесь, что my_cursor.description возвращает описание столбцов запроса в виде списка кортежей. Для каждого столбца возвращаются следующие данные:(name, type_code, display_size, internal_size, precision, scale, null_ok). Далее следует форматированный вывод на stdout( почти как printf в языке C).

print
print 'Database:',my_connection.tnsentry
print 
print "Used space by owner, object type, tablespace "
print "----------------------------------------------------------------------------------"
title_mask=('%-16s','%-16s','%-16s','%-8s','%-8s')
i=0
for column_description in my_cursor.description:
    print title_mask[i]%column_description[0],
    i=1+i
print ''
print "----------------------------------------------------------------------------------"
row_mask='%-16s %-16s %-16s %8.0f %8.0f '
for record in my_cursor.fetchall():
	print row_mask%record                  

В результате мы увидим что-то вроде:

Database: testdb

Used space by owner, object type, tablespace 
--------------------------------------------------------------------------------
OWNER            SEGMENT_TYPE     TABLESPACE_NAME  SIZE_BLOCKS SIZE_EXTENTS 
--------------------------------------------------------------------------------

ADU2             INDEX            USERS                 784       25 
ADU2             TABLE            USERS                 512       24 
ADUGKS           INDEX            DEVELOP_DATA          984      123 
ADUGKS           TABLE            DEVELOP_DATA          664       83 
ADUGPA           INDEX            USERS                 784       25 
ADUGPA           TABLE            USERS                 496       23 
AGNKS_SG         INDEX            USERS                 352       22 
AGNKS_SG         TABLE            USERS                 240       15 
ATU              INDEX            USERS                3968      244 
ATU              TABLE            DEVELOP_DATA            8        1 
ATU              TABLE            USERS                2688      160 
ATU1             INDEX            DEVELOP_DATA         1600      200 
ATU1             INDEX            USERS                 608       38 
ATU1             TABLE            DEVELOP_DATA         1032      129 
ATU1             TABLE            USERS                 544       34 
BUX              INDEX            DEVELOP_DATA           64        8 
BUX              TABLE            DEVELOP_DATA         1736      217 
DISP             INDEX            USERS                 400       25 
DISP             TABLE            USERS                 528       33 
EPE              INDEX            USERS                  80        5 
EPE              TABLE            USERS                  48        3 
EXZ              INDEX            USERS                1088       61 
EXZ              TABLE            DEVELOP_DATA            8        1 
EXZ              TABLE            USERS                 832       41 

Часть II. Запросы с параметрами.


Согласно спецификации Python Database API 2.0, для выполнения запросов с параметрами каждый модуль должен реализовывать переменную paramstyle, которая определяет каким образом будут передаваться параметры запросов. Текущая версия cx_Oracle(3.0) поддерживает режим 'named', то есть в модуле установлена переменная cx_Oracle.paramstyle='named' и можно создавать конструкции в запросах в виде:

select *  from all_users where USERNAME LIKE :S

При этом связывание параметров запроса со значениями можно можно выполнить двумя способами:

  • Именованный параметeр метода execute:
    cursor2.execute("select *  from all_users where USERNAME LIKE :S ",S='S%') 
  • Словарь {':переменная':значение,...}
    cursor2.execute("select *  from all_users where USERNAME LIKE :S ",{':S':'S%'})

Часть III. Анонимные блоки PL/SQL


Несмотря на существавания стандартов на язык SQL, реальные потребности администратора часто требуют использования нестандартных средств сервера(более того, написать приложение, работающее с сервером на стандартном SQL возможно только для весьма тривиальных приложений ), для Oracle таким нестандартным, но очень удобным механизмом является возможность исполнения анонимных блоков PL/SQL. Модуль сx_Oracle реализует этот механизм, который естественно не описан в спецификации Python Database API 2.0 .

Чтобы связать переменные блока PL/SQL c переменными языка PYTHON, в модуле сx_Oracle реализован класс var.Эекземпляр можно создать следующим образом:

var=my_cursor.var(cx_Oracle.DATETIME) 

Конструктор my_cursor.var(...) в качестве параметра требует указать тип создаваемой переменной. Варианты:

  • BINARY
  • DATETIME
  • FIXEDCHAR
  • LONGBINARY
  • LONGSTRING
  • NUMBER
  • ROWID
  • STRING
var=my_cursor.var(cx_Oracle.DATETIME) 
try:
    my_cursor.execute("""begin
    SELECT SYSDATE INTO :p_Value from dual;
    end;""",p_Value = var)
    
except cx_Oracle.DatabaseError,info:
    print "SQL Error:",info
    exit(0)

Очевидно, что теперь var содержит текущее время сервера.Доступ к значениям переменной выполняется с помощью метода var.getvalue():

CDATE=var.getvalue()
print 'Date: %02u/%02u/%4u'%(CDATE.day,CDATE.month,CDATE.year)
print 'Time: %02u:%02u:%02u'%(CDATE.hour,CDATE.minute,CDATE.second)

Этот пример демонстрирует также и форматирование даты и времени для экземпляра var. В результате напечатается нечто вроде:

Date: 12/05/2003
Time: 16:42:54

Всвязи с тем, что работа с типами времени и даты внутри сервера Oracle реализованы особенным образом ( независимо от ОС), модуль сx_Oracle реализует следующие функции для для преобразования значений дат и времени :

  • Date( year, month, day)
  • DateFromTicks( ticks)
  • Time( hour, minute, second)
  • TimeFromTicks( ticks)
  • Timestamp( year, month, day, hour, minute, second)
  • TimestampFromTicks( ticks)
var=my_cursor.var(cx_Oracle.DATETIME)
var.setvalue(0,cx_Oracle.Date( 2002, 02,12))
CDATE=var.getvalue()
print 'Date: %02u/%02u/%4u'%(CDATE.day,CDATE.month,CDATE.year)
print 'Time: %02u:%02u:%02u'%(CDATE.hour,CDATE.minute,CDATE.second)

Результат будет следующий:

Date: 12/02/2002
Time: 00:00:00

Ссылки


cx_Oracle-Python extension module that allows access to Oracle
Author: Anthony Tuininga http://computronix.com/utilities.shtml

Python Database API specification Python http://www.python.org/topics/database/DatabaseAPI-2.0.html


Листинги




Листинг 1.
Выполняем простой запрос


""
cx_Oracle demo
simple query
"""
__AUTHOR__='http://boomzoomer-comp.livejournal.com '
__COPYRIGHT__='boomzoomer 2003-2007.'_
"""
from sys import exit

try:
    import cx_Oracle
except ImportError,info:
    print "Import Error:",info
    sys.exit()
    
if cx_Oracle.version<'3.0':
    print "Very old version of cx_Oracle :",cx_Oracle.version
    sys.exit()

try:
    my_connection=cx_Oracle.connect('system/password@mydb')
except cx_Oracle.DatabaseError,info:
    print "Logon  Error:",info
    exit(0)
    
my_cursor=my_connection.cursor()
try:
    my_cursor.execute("""
    SELECT OWNER,SEGMENT_TYPE,TABLESPACE_NAME,SUM(BLOCKS)SIZE_BLOCKS,
    COUNT(*) SIZE_EXTENTS FROM DBA_EXTENTS
    GROUP BY OWNER,SEGMENT_TYPE,TABLESPACE_NAME
    """)
except cx_Oracle.DatabaseError,info:
    print "SQL Error:",info
    exit(0)
    
print
print 'Database:',my_connection.tnsentry
print 
print "Used space by owner, object type, tablespace "
print "-----------------------------------------------------------"
title_mask=('%-16s','%-16s','%-16s','%-8s','%-8s')
i=0
for column_description in my_cursor.description:
    print title_mask[i]%column_description[0],
    i=1+i
print ''
print "------------------------------------------------------------"
row_mask='%-16s %-16s %-16s %8.0f %8.0f '
for record in my_cursor.fetchall():
	print row_mask%record
for column_description in my_cursor.description:
    print column_description

Листинг 2.

Запрос с параметрами

""
cx_Oracle demo
query with parameters
"""
__AUTHOR__='http://boomzoomer-comp.livejournal.com '
__COPYRIGHT__='boomzoomer 2003-2007.'

from sys import exit

try:
    import cx_Oracle
except ImportError,info:
    print "Import Error:",info
    sys.exit()
    
if cx_Oracle.version<'3.0':
    print "Very old version of cx_Oracle :",cx_Oracle.version
    sys.exit()

try:
    my_connection=cx_Oracle.connect('system/manager@test_db')
except cx_Oracle.DatabaseError,info:
    print "Logon  Error:",info
    exit(0)
    
my_cursor=my_connection.cursor()
try:
    my_cursor.execute("""
    SELECT OWNER,SEGMENT_TYPE,TABLESPACE_NAME,SUM(BLOCKS)SIZE_BLOCKS,
    COUNT(*) SIZE_EXTENTS FROM DBA_EXTENTS
        WHERE OWNER LIKE :S
    GROUP BY OWNER,SEGMENT_TYPE,TABLESPACE_NAME
    """,S='SYS%')
except cx_Oracle.DatabaseError,info:
    print "SQL Error:",info
    exit(0)
    
print
print 'Database:',my_connection.tnsentry
print 
print "Used space by owner, object type, tablespace "
print "-----------------------------------------------------------"
title_mask=('%-16s','%-16s','%-16s','%-8s','%-8s')
i=0
for column_description in my_cursor.description:
    print title_mask[i]%column_description[0],
    i=1+i
print ''
print "------------------------------------------------------------"
row_mask='%-16s %-16s %-16s %8.0f %8.0f '
for record in my_cursor.fetchall():
	print row_mask%record

© http://boomzoomer-comp.livejournal.com 2003-2007

Comments

(no subject) - [info]vassalswhelp - Sep. 29th, 2008 10:12 pm (UTC)

Profile

[info]boomzoomer_comp
boomzoomer_comp

Latest Month

December 2008
S M T W T F S
 123456
78910111213
14151617181920
21222324252627
28293031   

Page Summary

Powered by LiveJournal.com
Designed by Tiffany Chow