26
Developing Informix Applications in Python Carsten Haese Unique Systems, Inc. Informix Forum 2006 Washington, DC December 8-9, 2006

Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

  • Upload
    dangnga

  • View
    220

  • Download
    4

Embed Size (px)

Citation preview

Page 1: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

Developing InformixApplications in Python

Carsten HaeseUnique Systems, Inc.

Informix Forum 2006Washington, DC

December 8-9, 2006

Page 2: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

2Developing Informix Applications in Python

OverviewOverview

● Python FeaturesPython Features● InformixDB FeaturesInformixDB Features● Installing InformixDBInstalling InformixDB● Interactive Tour of InformixDBInteractive Tour of InformixDB● ““Real World” ExampleReal World” Example● ConclusionConclusion

Page 3: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

3Developing Informix Applications in Python

Python FeaturesPython Features

● Open SourceOpen Source

● Cross-PlatformCross-Platform

● Easy to learnEasy to learn● Dynamic LanguageDynamic Language

● Interactive ConsoleInteractive Console

● Clean SyntaxClean Syntax

● Helpful user communityHelpful user community

● VersatileVersatile● Small tasks or large applicationsSmall tasks or large applications

● Stand-alone or embeddedStand-alone or embedded

● Console, GUI, or web applicationsConsole, GUI, or web applications

● Rich standard library and 3Rich standard library and 3rdrd party extensionsparty extensions

● ExpressiveExpressiveDuck typing, Iterators, HOFs, OOP, Duck typing, Iterators, HOFs, OOP, Powerful data types, exception handling, Powerful data types, exception handling, memory managementmemory management

● Fosters Reusable CodeFosters Reusable Code

● AgileAgile

● Rapid Application Rapid Application DevelopmentDevelopment

● Standardized database APIStandardized database API

Page 4: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

4Developing Informix Applications in Python

InformixDB FeaturesInformixDB Features

● DB-API 2.0 compliantDB-API 2.0 compliant

● Portable (POSIX and Win32 Platforms)Portable (POSIX and Win32 Platforms)

● Multiple connectionsMultiple connections

● Parametrized queriesParametrized queries

● Statement caching and prepared statementsStatement caching and prepared statements

● Access to sqlcode and sqlerrdAccess to sqlcode and sqlerrd

● Update, delete, and insert cursorsUpdate, delete, and insert cursors

● Scroll cursors and cursors with holdScroll cursors and cursors with hold

● Supports all IDS data types, including Smart Large Objects, and Supports all IDS data types, including Smart Large Objects, and UDTsUDTs

Page 5: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

5Developing Informix Applications in Python

Installing InformixDBInstalling InformixDB

Prerequisites:Prerequisites:

Python 2.2+Python 2.2+

Informix Client SDKInformix Client SDK

Get InformixDB from informixdb.sourceforge.netGet InformixDB from informixdb.sourceforge.net

POSIX Installation: Compile from sourcePOSIX Installation: Compile from source

python setup.py build_extpython setup.py build_ext

python setup.py installpython setup.py install (as root)(as root)

Windows: Installers are provided for Python 2.4+Windows: Installers are provided for Python 2.4+

Page 6: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

6Developing Informix Applications in Python

Establishing a ConnectionEstablishing a Connection

import informixdbimport informixdbconn = informixdb.connect(”stores_demo”, ”informix”, ”pw”)conn = informixdb.connect(”stores_demo”, ”informix”, ”pw”)

Page 7: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

7Developing Informix Applications in Python

Static SQL QueryStatic SQL Query

cur = conn.cursor()cur = conn.cursor()cur.execute(“select * from customer”)cur.execute(“select * from customer”)

Page 8: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

8Developing Informix Applications in Python

Fetching Data RowsFetching Data Rows

cur.execute(“select * from customer”)cur.execute(“select * from customer”)print cur.fetchone()print cur.fetchone()print cur.fetchmany(5)print cur.fetchmany(5)print cur.fetchall()print cur.fetchall()

Page 9: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

9Developing Informix Applications in Python

SQL Query with ParametersSQL Query with Parameters

start_date = raw_input(“Start Date: “)start_date = raw_input(“Start Date: “)end_date = raw_input(“End Date: “)end_date = raw_input(“End Date: “)

Question mark placeholders:Question mark placeholders:

cur.execute(“””cur.execute(“”” select * from orders where order_date between ? and ?select * from orders where order_date between ? and ?“””“””, (start_date, end_date) ), (start_date, end_date) )

Numeric placeholders:Numeric placeholders:

cur.execute(“””cur.execute(“”” select * from orders where order_date between :1 and :2select * from orders where order_date between :1 and :2“””“””, (start_date, end_date) ), (start_date, end_date) )

Page 10: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

10Developing Informix Applications in Python

SQL Query with ParametersSQL Query with ParametersContinuedContinued

Named placeholders:Named placeholders:

cur.execute(“””cur.execute(“”” select * from orders where order_date between :start_date and :end_dateselect * from orders where order_date between :start_date and :end_date“””“””, {'start_date':start_date, 'end_date':end_date} ), {'start_date':start_date, 'end_date':end_date} )

Using Using locals()locals()makes named parameters look like host variables:makes named parameters look like host variables:

cur.execute(“””cur.execute(“”” select * from orders where order_date between :start_date and :end_dateselect * from orders where order_date between :start_date and :end_date“””“””, locals() ), locals() )

Page 11: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

11Developing Informix Applications in Python

Looping through Data RowsLooping through Data Rows

Doing it the hard way:Doing it the hard way:

cur.execute("select * from orders where customer_num=104")cur.execute("select * from orders where customer_num=104")row = cur.fetchone()row = cur.fetchone()while row != None:while row != None: print "Order %s was placed on %s." % (row[0], row[1])print "Order %s was placed on %s." % (row[0], row[1]) row = cur.fetchone()row = cur.fetchone()

Using cursors as iterators is much easier:Using cursors as iterators is much easier:

cur.execute("select * from orders where customer_num=104")cur.execute("select * from orders where customer_num=104")for row in cur:for row in cur: print "Order %s was placed on %s." % (row[0], row[1])print "Order %s was placed on %s." % (row[0], row[1])

Page 12: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

12Developing Informix Applications in Python

Column Access AlternativesColumn Access Alternatives

By default, rows are returned as tuples according to DB-API standard, which By default, rows are returned as tuples according to DB-API standard, which requires column access by number. Dictionary cursors return rows as requires column access by number. Dictionary cursors return rows as dictionaries that allow column access by name:dictionaries that allow column access by name:

dictcur = conn.cursor(rowformat=informixdb.ROW_AS_DICT)dictcur = conn.cursor(rowformat=informixdb.ROW_AS_DICT)dictcur.execute("select * from orders where customer_num=104")dictcur.execute("select * from orders where customer_num=104")for row in dictcur:for row in dictcur: print "Order %s was placed on %s.”,(row['order_num'],print "Order %s was placed on %s.”,(row['order_num'],

row['order_date']) row['order_date'])

Object cursors offer a more concise way of accessing columns by name:Object cursors offer a more concise way of accessing columns by name:

objcur = conn.cursor(rowformat=informixdb.ROW_AS_OBJECT)objcur = conn.cursor(rowformat=informixdb.ROW_AS_OBJECT)objcur.execute("select * from orders where customer_num=104")objcur.execute("select * from orders where customer_num=104")for row in objcur:for row in objcur: print "Order %s was placed on %s." % (row.order_num, print "Order %s was placed on %s." % (row.order_num,

row.order_date) row.order_date)

Page 13: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

13Developing Informix Applications in Python

Named CursorNamed Cursor

Explicitly named cursors are useful as update or delete cursors:Explicitly named cursors are useful as update or delete cursors:

price_increase = {'SMT':4, 'HSK':5, 'SHM':3}price_increase = {'SMT':4, 'HSK':5, 'SHM':3}updcur = conn.cursor(name="updcur", rowformat=informixdb.ROW_AS_OBJECT)updcur = conn.cursor(name="updcur", rowformat=informixdb.ROW_AS_OBJECT)updcur.execute("select * from stock for update of unit_price")updcur.execute("select * from stock for update of unit_price")for row in updcur:for row in updcur: increase = price_increase.get(row.manu_code, None)increase = price_increase.get(row.manu_code, None) if increase != None:if increase != None: newprice = row.unit_price * (1.0+increase/100.0)newprice = row.unit_price * (1.0+increase/100.0) cur.execute("update stock set unit_price=? where current of updcur", cur.execute("update stock set unit_price=? where current of updcur",

[newprice] ) [newprice] )

Page 14: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

14Developing Informix Applications in Python

Bulk ExecutionBulk Execution

names = [names = [ (“Jonathan”, “Leffler”),(“Jonathan”, “Leffler”), (“Darryl”, “Priest”),(“Darryl”, “Priest”), (“Carsten”, “Haese”)(“Carsten”, “Haese”)]]

cur.executemany(“””cur.executemany(“”” insert into customer(fname,lname) values(?,?)insert into customer(fname,lname) values(?,?)“””“””, names ), names )

For insert statements, executemany employs an insert cursor “under the hood” when For insert statements, executemany employs an insert cursor “under the hood” when possible.possible.

Page 15: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

15Developing Informix Applications in Python

Prepared StatementsPrepared Statements

get_manu_name = conn.cursor()get_manu_name = conn.cursor()get_manu_name.prepare(“””get_manu_name.prepare(“”” select manu_name from manufact where manu_code=?select manu_name from manufact where manu_code=?“””“””))

while True:while True: manu_code = raw_input(“Enter a manufacturer code: “)manu_code = raw_input(“Enter a manufacturer code: “) if manu_code==””: breakif manu_code==””: break get_manu_name.execute(None, [manu_code] )get_manu_name.execute(None, [manu_code] ) manu_name = get_manu_name.fetchone()[0]manu_name = get_manu_name.fetchone()[0] print manu_nameprint manu_name

Page 16: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

16Developing Informix Applications in Python

TransactionsTransactions

By default, a connection is always in a transaction. Committing or rolling By default, a connection is always in a transaction. Committing or rolling back the current transaction begins a new transaction.back the current transaction begins a new transaction.

conn.commit()conn.commit()conn.rollback()conn.rollback()

Sometimes it's useful to work outside of a transaction:Sometimes it's useful to work outside of a transaction:

conn.autocommit = Trueconn.autocommit = True

Page 17: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

17Developing Informix Applications in Python

Scroll CursorScroll Cursor

scrollcurs = conn.cursor(scroll=True)scrollcurs = conn.cursor(scroll=True)scrollcurs.execute(“select * from customer order by customer_num”)scrollcurs.execute(“select * from customer order by customer_num”)scrollcurs.scroll(10,”absolute”)scrollcurs.scroll(10,”absolute”)print scrollcurs.fetchone()print scrollcurs.fetchone()scrollcurs.scroll(-5,”relative”)scrollcurs.scroll(-5,”relative”)print scrollcurs.fetchone()print scrollcurs.fetchone()

Page 18: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

18Developing Informix Applications in Python

Date and Datetime Columns/Date and Datetime Columns/Accessing SQLERRDAccessing SQLERRD

InformixDB uses Python’s datetime module for handling date and InformixDB uses Python’s datetime module for handling date and datetime values.datetime values.

import datetimeimport datetimetoday = datetime.date.today()today = datetime.date.today()cur.execute(“””cur.execute(“”” insert into orders(customer_num,order_date)insert into orders(customer_num,order_date) values(?,?)values(?,?)“””“””, [104,today] ), [104,today] )

# Read out sqlerrd to get the serial number of the newly inserted order# Read out sqlerrd to get the serial number of the newly inserted orderprint cur.sqlerrdprint cur.sqlerrd

Page 19: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

19Developing Informix Applications in Python

Error HandlingError Handling

By default, error conditions raise Python exceptions:By default, error conditions raise Python exceptions:

my_sqlcode = 0my_sqlcode = 0try:try: cur.execute("sleect * from systables")cur.execute("sleect * from systables")except informixdb.Error, e:except informixdb.Error, e: my_sqlcode = e.sqlcodemy_sqlcode = e.sqlcodeprint my_sqlcodeprint my_sqlcode

An An errorhandlererrorhandler callback can be set up to customize error handling. callback can be set up to customize error handling.

Page 20: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

20Developing Informix Applications in Python

Describing a QueryDescribing a Query

If a query produces a result set (e.g. SELECT), the cursor’s If a query produces a result set (e.g. SELECT), the cursor’s description description attribute describes the result columns. If a query attribute describes the result columns. If a query doesn’t produce a result set, doesn’t produce a result set, descriptiondescription is is NoneNone..

cur.execute("select * from systables")cur.execute("select * from systables")print cur.descriptionprint cur.description

Page 21: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

21Developing Informix Applications in Python

Features Not CoveredFeatures Not Covered

● Interval types, date arithmetic, interval arithmeticInterval types, date arithmetic, interval arithmetic● Working with simple large objectsWorking with simple large objects● Working with opaque typesWorking with opaque types● Using smart large objects as file-like objectsUsing smart large objects as file-like objects

Page 22: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

22Developing Informix Applications in Python

““Real World” ExampleReal World” Exampleimport informixdbimport informixdbfrom itertools import groupbyfrom itertools import groupbyfrom operator import attrgetterfrom operator import attrgetter

conn = informixdb.connect("stores_demo")conn = informixdb.connect("stores_demo")

def report_rows(start_date, end_date):def report_rows(start_date, end_date): main_cur = conn.cursor(rowformat=informixdb.ROW_AS_OBJECT)main_cur = conn.cursor(rowformat=informixdb.ROW_AS_OBJECT) main_cur.execute("""main_cur.execute(""" select customer.*, orders.*, items.*select customer.*, orders.*, items.* from customer, orders, itemsfrom customer, orders, items where items.order_num = orders.order_numwhere items.order_num = orders.order_num and customer.customer_num = orders.customer_numand customer.customer_num = orders.customer_num and orders.order_date between :start_date and :end_dateand orders.order_date between :start_date and :end_date order by customer.customer_num, orders.order_numorder by customer.customer_num, orders.order_num """, locals() )""", locals() ) for row in main_cur:for row in main_cur: row.unit_price = row.total_price / row.quantityrow.unit_price = row.total_price / row.quantity yield rowyield row

start_date = raw_input("Start Date: ")start_date = raw_input("Start Date: ")end_date = raw_input("End Date: ")end_date = raw_input("End Date: ")

cust_grouping = groupby(report_rows(start_date, end_date),cust_grouping = groupby(report_rows(start_date, end_date), attrgetter("customer_num", "fname", "lname"))attrgetter("customer_num", "fname", "lname"))for (cust_code, fname, lname), cust_rows in cust_grouping:for (cust_code, fname, lname), cust_rows in cust_grouping: cust_total = 0cust_total = 0 print "Customer: %s - %s %s" % (cust_code, fname, lname)print "Customer: %s - %s %s" % (cust_code, fname, lname) printprint ord_grouping = groupby(cust_rows, attrgetter("order_num", "order_date"))ord_grouping = groupby(cust_rows, attrgetter("order_num", "order_date")) for (order_num, order_date), ord_rows in ord_grouping:for (order_num, order_date), ord_rows in ord_grouping: print " Order: %-10s Order Date: %s" % (order_num,print " Order: %-10s Order Date: %s" % (order_num, order_date.strftime("%m/%d/%Y"))order_date.strftime("%m/%d/%Y")) printprint for row in ord_rows:for row in ord_rows: print " %-10s %5d %7s %7s" % (print " %-10s %5d %7s %7s" % ( row.manu_code+str(row.stock_num), row.quantity, row.unit_price,row.manu_code+str(row.stock_num), row.quantity, row.unit_price, row.total_price)row.total_price) cust_total += row.total_pricecust_total += row.total_price printprint print "Customer Total: %s" % cust_totalprint "Customer Total: %s" % cust_total print "-"*80print "-"*80 printprint

Page 23: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

23Developing Informix Applications in Python

ConclusionConclusion

Thanks to its versatility and agility, Python is an attractive and productive programming language for developing Informix applications - and Python is fun!

Page 24: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

24Developing Informix Applications in Python

LinksLinks

● Python’s Home PagePython’s Home Pagehttp://www.python.org/http://www.python.org/

● Information on DB Programming in PythonInformation on DB Programming in Pythonhttp://www.python.org/topics/database/http://www.python.org/topics/database/

● Python DB-API specification, version 2.0Python DB-API specification, version 2.0http://www.python.org/peps/pep-0249.htmlhttp://www.python.org/peps/pep-0249.html

● InformixDB on SourceforgeInformixDB on Sourceforgehttp://informixdb.sourceforge.net/http://informixdb.sourceforge.net/

Page 25: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

25Developing Informix Applications in Python

AcknowledgmentsAcknowledgments

● Guido van Rossum and many othersGuido van Rossum and many othersfor creating Python,for creating Python,

● Greg Stein, Michael Lorton, Bertil Reinhammar, and Greg Stein, Michael Lorton, Bertil Reinhammar, and Stephen J. Turner,Stephen J. Turner,for originally developing and maintaining for originally developing and maintaining InformixDBInformixDB

● Daniel Smertnig,Daniel Smertnig,for contributing improvements to InformixDBfor contributing improvements to InformixDB

Page 26: Developing Informix Applications in Python · Developing Informix Applications in Python 11 Looping through Data Rows Doing it the hard way: cur.execute("select * from orders where

26Developing Informix Applications in Python

Developing InformixApplications in Python

Carsten HaeseUnique Systems, Inc.

Informix Forum 2006Washington, DC

December 8-9, 2006