Professional Documents
Culture Documents
17 Dec 2002 The Python Database API is a standard specification for the implementation of a Python interface to a database management system. The DB2 module is an implementation of the Python Database standard. This tutorial covers the entire API and provides sample code that can be run in Python's interactive mode. It uses the sample database that ships with DB2 UDB 8.1 Enterprise Edition for Linux.
Section 1. Introduction
Should I take this tutorial?
This tutorial was written with two types of people in mind: Python programmers who want to access DB2 V8.1 databases from their Python programs. Database developers who are interested in Python and want to see how it works with DB2. Python is a great tool to use with DB2. It combines the ability to quickly and simply access a DB2 database with the power to perform more complex tasks that require a general purpose programming language. This tutorial shows you everything you need to know to interact with DB2 V8.1 using the Python programming language. In particular, you'll learn about the Python DB2 module, which allows you to connect to
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved. Trademarks Page 1 of 26
developerWorks
ibm.com/developerWorks
a DB2 database, execute queries, fetch results, and commit or rollback transactions. To keep things as simple as possible, you won't have to build an entire application or write a lot of code. Instead, you'll be shown short, simple examples that can be run directly in Python using the sample database that comes with DB2. By the end of the tutorial you will have received a thorough introduction to the entire Python DB2 interface. To get the most out of this tutorial, you should be familiar with basic relational database concepts and SQL, and have some programming knowledge. Experience with DB2 and Python would be helpful, but are not essential. If you can formulate an SQL query and understand basic programming logic, you should be able to follow this tutorial.
Tools
This tutorial uses the following software. Make sure they are installed and running correctly before starting this tutorial: DB2 UDB Version 8.1. You can download a DB2 from the developerWorks downloads page. The tutorial uses the SAMPLE database that is created during a typical DB2 installation. Python (version 2.2 or higher is recommended).
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 2 of 26
ibm.com/developerWorks
developerWorks
PyDB2 Package, which contains the Python DB2 interface module and utilities. Also see Project: PyDB2, which contains additional information about the package. Over the course of the tutorial we will explore the entire database API and some additional utilities. Along the way you will be given code examples that you can execute yourself. All the examples are demonstrated using Python's interactive mode in order to illustrate the results of each command. The tutorial examples were tested against DB2 UDB 8.1 Enterprise Edition for Linux, using the SAMPLE database. Specifically, DB2 8.1 and Python 2.2.2 were installed on Mandrake 9.0. The techniques shown in this tutorial should work equally well with previous versions of DB2, as well as versions running on other platforms, including RedHat 7.2 or higher, SuSE 7.3 or higher, and SCO Linux 4.0 or higher. Note that the DB2 UDB SAMPLE database is not automatically installed when you install DB2. You can install the SAMPLE database using the First Steps graphical utility, or the db2sampl command line utility. See Resources for detailed information on DB2 Information Center.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 3 of 26
developerWorks
ibm.com/developerWorks
Sybase, or DB2. Each module is usually tailored to the specific DBMS for which it provides an interface, though there is also an ODBC module that allows access to a variety of storage mechanisms. The Python DB2 module was written by Man-Yong (Bryan) Lee, and complies with the latest Python DB-API standard. The Python DB2 module is pretty much the only game in town when it comes to accessing DB2 from Python. In order to understand how to use this module, we're going to take a quick look at the Python language and some of its features. Then we'll look at the DB2 module and see how to connect to a DB2 database, execute queries, interact with the results, and control transactions. You should try out the examples yourself using Python's interactive mode.
Interactive mode
Python can be used to execute program files, or it can be run interactively, in which you enter lines of code and receive an immediate response from the Python interpreter. To start Python in interactive mode, simply type python at your operating system command line. Python will then display a few lines of information, followed by the Python command prompt (>>>):
$ python Python 2.2.2 (#1, Oct 28 2002, 17:22:19) [GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
Working with Python interactively is very similar to working with a Linux or DOS shell. At the Python prompt you can type in a line of Python code, press the Enter key, and get a response back. For example, you can use Python as a simple calculator, adding two integers together:
>>> 2 + 2 4 >>>
As you can see in the previous example, Python responded by displaying the sum of the two values, followed by another prompt. You can also assign values to variables and then manipulate the variables:
>>> a = 3 >>> b = 5 >>> a * b 15 >>>
To leave the Python interpreter and return to the command line, press Ctrl-D
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved. Trademarks Page 4 of 26
ibm.com/developerWorks
developerWorks
Multi-line commands
Some Python code requires multiple lines, such as the block of code that gets executed inside a for loop. In these cases, the Python shell displays a continuation prompt (...) for each subsequent line. Notice also that a block of code is determined by its level of indentation, rather than curly braces or BEGIN and END keywords. In the following example, the lines of code that make up the for loop block are all indented to the same level (typically four spaces). Pressing Enter twice in a row tells Python that you're done entering code and are ready for it to be executed:
>>> for n in range(4): ... print "The first value of n:", n ... print "Multiplied by itself:", n * n ... print "-----------------------" ... The first value of n: 0 Multiplied by itself: 0 ----------------------The first value of n: 1 Multiplied by itself: 1 ----------------------The first value of n: 2 Multiplied by itself: 4 -----------------------
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 5 of 26
developerWorks
ibm.com/developerWorks
The built-in range() function used in the previous example returns a list of integer values, which the for loop then iterates over, temporarily assigning each value to the n variable. In Python, a list is denoted by square brackets enclosing a sequence of items separated by commas. In the following example, executing the range() function by itself returns a list of integers:
>>> range(4) [0, 1, 2, 3]
Python has a rich set of built-in object types, and the Python DB2 interface makes heavy use of certain ones. So you need to be able to at least recognize them and understand what they represent. Therefore, the following pages will describe the more common types, such as integers, floats, strings, lists, tuples, and modules.
Strings in Python are sequences of characters. You create a string literal by enclosing the characters in single ('), double (") or triple (''' or """) quotes. The triple-quoted forms preserve embedded new lines:
>>> sql1 = 'SELECT * FROM ORG' >>> sql2 = "SELECT * FROM ORG" >>> sql3 = """SELECT * ... FROM ORG ... WHERE DEPTNUMB > 20""" >>> sql3 'SELECT *\nFROM ORG\nWHERE DEPTNUMB > 20' >>>
A Python string is an object that has several built-in capabilities. For example, one of them is the ability to return a copy of itself with all uppercase letters. These capabilities are known as methods. You invoke a method of an object, such as a string, using a dot syntax. That is, you type the name of the variable (which in this
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 6 of 26
ibm.com/developerWorks
developerWorks
case is a reference to a string object) followed by the dot (.) operator, then the name of the method followed by opening and closing parentheses:
>>> sql = 'select * from org' >>> sql.upper() 'SELECT * FROM ORG' >>>
Lists and tuples can both be referenced by index position (starting with zero). And lists have methods that tuples do not, such as the append() method for adding a new element to the end of the list:
>>> 1 >>> (2, >>> >>> [1, >>> mylist[0] nested[1] 'Shoe') mylist.append("Shut") mylist 2, 'Buckle', 'Shoe', 'Shut']
None
Python has a None type used to represent null or nil. SQL has a NULL value that is used to represent a missing or unknown value. When a DB2 query returns NULL values, they are represented in Python by the None type. None is also quite often used to represent a certain condition in Python. For example, one of the DB2 interface functions will return None when there are no more rows to fetch from a query result set.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 7 of 26
developerWorks
ibm.com/developerWorks
Modules
Modules are simply text files containing Python code that is intended to be used by other programs or at the interactive prompt. To make use of a module, you load it into memory with the import statement. While the physical file has a .py suffix, Python refers to the module without the suffix. Here is how you import the DB2 module (whose filename is DB2.py):
>>> import DB2 >>>
Once a module is imported, you may use any of its contents. To do so, you simply preface the variable's name with the module name separated by a dot (.):
>>> DB2.apilevel '2.0' >>> DB2.paramstyle 'qmark' >>>
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
ibm.com/developerWorks
developerWorks
7. 8. 9.
Let's look at a simple example; then we'll go into the details of each step.
The Python code is straightforward and hardly needs explaining. Nevertheless, there are several options and variations that you should understand, starting with establishing a connection to a particular database.
Connection objects
The first step in accessing a DB2 database is to establish a connection to a particular data source, as a particular user. To do so you create a connection object, passing in the required arguments:
>>> import DB2 >>> conn = DB2.connect(dsn='sample', uid='db2inst1', pwd='******') >>>
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 9 of 26
developerWorks
ibm.com/developerWorks
dsn - data source name, required uid - user name, required pwd - password, required autocommit - optional, defaults to True connecttype - optional, defaults to 1 When a connection object is no longer needed, you should call its close() method, which will free up resources. The next panel describes all the parameters in detail.
Connection parameters
The data source (dsn), user name (uid), and password (pwd) parameters should be obvious to anyone familiar with databases. The password argument shown in the examples has been obscured. You should use appropriate values for your own environment. A real application would likely store these arguments in a configuration file, accept them as command line options, or prompt the user for values. The autocommit parameter allows you to control the automatic committing of transactions. By default, a connection object will automatically commit each interaction with the database. If you want to determine your own transaction boundaries, you can supply a different autocommit argument value or use the connection's autocommit() method to toggle the autocommit feature:
>>> conn.autocommit() # Get the current value. 1 >>> conn.autocommit(False) # Set to False. 0 >>> conn.autocommit(True) # Set to True. 1 >>>
To support transactions, the connection object provides commit() and rollback() methods. These will be discussed with Transactions . The connecttype parameter takes one of two values: 1 sets the connection type to a remote unit of work (default); 2 sets it to a distributed unit of work.
Cursor objects
Once a connection to the database is established, you can use it to create one or
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 10 of 26
ibm.com/developerWorks
developerWorks
more cursors. A cursor is used to send SQL statements (SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER) to the database. To create a cursor, you simply call the connection object's cursor() method, which returns a cursor object:
>>> import DB2 >>> conn = DB2.connect(dsn='sample', uid='db2inst1', pwd='******') >>> curs = conn.cursor() >>>
Cursor objects provide an execute() method that accepts an SQL statement. When called, the SQL statement is sent to the DBMS to be executed. If the statement was a SELECT query, the results can then be retrieved using one of the fetch methods: fetchone(), fetchmany(), and fetchall(). We'll look at the fetch methods in detail next. Note that the execute() function does not return a value:
>>> >>> >>> >>> >>> import DB2 conn = DB2.connect(dsn='sample', uid='db2inst1', pwd='******') curs = conn.cursor() curs.execute('SELECT * FROM ORG')
Fetching results
Once a SELECT query has been executed by the cursor object, the results can be retrieved, or fetched, from the DBMS. The fetchone() method returns a single row from the SELECT result set. The row's contents are returned in the form of a Python tuple (not to be confused with a relational tuple):
>>> curs.execute('SELECT * FROM ORG') >>> curs.fetchone() (10, 'Head Office', 160, 'Corporate', 'New York') >>>
The fetchall() and fetchmany() methods return a list of tuples, with each tuple representing one row. The fetchmany() method accepts a single argument specifying the maximum number of rows to return:
>>> curs.execute('SELECT * FROM ORG') >>> curs.fetchmany(3) [(10, 'Head Office', 160, 'Corporate', 'New York'), (15, 'New England', 50, 'Eastern', 'Boston'), (20, 'Mid Atlantic', 10, 'Eastern', 'Washington')] >>>
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 11 of 26
developerWorks
ibm.com/developerWorks
If more rows are specified than are available, fetchmany() returns as many rows as it can:
>>> curs.execute('SELECT * FROM ORG') >>> curs.fetchmany(300) [(10, 'Head Office', 160, 'Corporate', 'New York'), (15, 'New England', 50, 'Eastern', 'Boston'), (20, 'Mid Atlantic', 10, 'Eastern', 'Washington'), (38, 'South Atlantic', 30, 'Eastern', 'Atlanta'), (42, 'Great Lakes', 100, 'Midwest', 'Chicago'), (51, 'Plains', 140, 'Midwest', 'Dallas'), (66, 'Pacific', 270, 'Western', 'San Francisco'), (84, 'Mountain', 290, 'Western', 'Denver')] >>>
Cursor position
Every time a row is fetched, the position in the result set moves to the next row. That means the entire set of rows can be returned by repeated calls to fetchone(), or a combination of any of the fetch methods. Once a cursor has been exhausted, subsequent calls to fetchone() return None; fetchmany() and fetchall() return empty lists ([]):
>>> curs.execute('SELECT * FROM ORG') >>> while True: ... org = curs.fetchone() ... if org is None: ... print "**** The End ****" ... break ... print org ... (10, 'Head Office', 160, 'Corporate', 'New York') (15, 'New England', 50, 'Eastern', 'Boston') (20, 'Mid Atlantic', 10, 'Eastern', 'Washington') (38, 'South Atlantic', 30, 'Eastern', 'Atlanta') (42, 'Great Lakes', 100, 'Midwest', 'Chicago') (51, 'Plains', 140, 'Midwest', 'Dallas') (66, 'Pacific', 270, 'Western', 'San Francisco') (84, 'Mountain', 290, 'Western', 'Denver') **** The End **** >>> curs.fetchmany() [] >>> curs.fetchall() [] >>>
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 12 of 26
ibm.com/developerWorks
developerWorks
... CREATE TABLE TEST ( ... No CHARACTER(03) ... Name VARCHAR(20) ... Desc VARCHAR(100), ... PRIMARY KEY(No) ... );""" >>> print sql CREATE TABLE TEST ( No CHARACTER(03) Name VARCHAR(20) Desc VARCHAR(100), PRIMARY KEY(No) ); >>> curs.execute(sql) >>>
Attempting to fetch a result from any type of query other than a SELECT query will raise a Python exception. For example, this is what happens if we call fetchall() after the previous CREATE TABLE query:
>>> curs.fetchall() Traceback (most recent call last): File "<input>", line 1, in ? File "/usr/local/lib/python2.2/site-packages/DB2.py", line 415, in fetchall one_row = self.fetchone() File "/usr/local/lib/python2.2/site-packages/DB2.py", line 350, in fetchone raw_data = self._cs.fetchone() error: No data >>>
The description property is a tuple of tuples, describing each column in the result set. Each inner tuple represents one column and contains seven items of information: 1. 2. column name type code
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 13 of 26
developerWorks
ibm.com/developerWorks
3. 4. 5. 6. 7.
display size internal size precision scale (zero for non-numeric types) NULL values allowed
Because the column's type code isn't very meaningful, the DB2 module also provides a description2 property for cursors, which substitutes a text value for the type code:
>>> curs.description2 (('DEPTNUMB', 'SQL_SMALLINT', 6, 6, 5, 0, 0), ('DEPTNAME', 'SQL_VARCHAR', 14, 14, 14, 0, 1), ('MANAGER', 'SQL_SMALLINT', 6, 6, 5, 0, 1), ('DIVISION', 'SQL_VARCHAR', 10, 10, 10, 0, 1), ('LOCATION', 'SQL_VARCHAR', 13, 13, 13, 0, 1)) >>>
The db2util module makes extensive use of the column information provided by the description property to create a nice format for query results. The following example illustrates one use of this in the cprint() function:
>>> from PyDB2 import db2util >>> import DB2 >>> conn = DB2.connect(dsn='sample', uid='db2inst1', pwd='******') >>> curs = conn.cursor() >>> curs.execute('SELECT * FROM ORG') >>> db2util.cprint(curs, curs.fetchall()) DEPTNUMB DEPTNAME MANAGER DIVISION LOCATION -------- -------------- ------- ---------- ------------10 Head Office 160 Corporate New York 15 New England 50 Eastern Boston 20 Mid Atlantic 10 Eastern Washington 38 South Atlantic 30 Eastern Atlanta 42 Great Lakes 100 Midwest Chicago 51 Plains 140 Midwest Dallas 66 Pacific 270 Western San Francisco
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 14 of 26
ibm.com/developerWorks
developerWorks
84 Mountain >>>
290 Western
Denver
Query parameters
So far we've shown very simple queries in our examples. But most applications will need to execute queries with variable data, based on user input or values determined at runtime. The DB2 interface supports the use of parameters within queries, and will make sure that string parameter values are properly quoted. The particular parameter style supported is the question mark style, where question marks are used as placeholders for parameters. To make use of parameters in your queries, simply insert question marks in your SQL statement wherever you want a parameter value to appear. Then you supply the cursor's execute() method with a tuple of parameter values along with your SQL statement. The following example demonstrates one use of this technique:
>>> sql = 'SELECT * FROM ORG WHERE DEPTNUMB = ? OR DIVISION = ?' >>> dept = 84 >>> div = 'Midwest' >>> curs.execute(sql, (dept, div)) >>> curs.fetchall() [(42, 'Great Lakes', 100, 'Midwest', 'Chicago'), (51, 'Plains', 140, 'Midwest', 'Dallas'), (84, 'Mountain', 290, 'Western', 'Denver')] >>>
Note that parameters can be used with any SQL statement and are not limited to SELECT queries. In fact, parameters can be quite handy with INSERT queries, which we will see in the next panel where we talk about executing multiple SQL statements.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 15 of 26
developerWorks
ibm.com/developerWorks
As you can imagine, the executemany() method doesn't make much sense with a SELECT query. Instead, you would use executemany() to perform multiple INSERT or UPDATE queries. Let's take a look at the executemany() method in action. In an earlier example we created a TEST table:
>>> sql = """ ... CREATE TABLE TEST ( ... No CHARACTER(03) ... Name VARCHAR(20) ... Desc VARCHAR(100), ... PRIMARY KEY(No) ... );""" >>> curs.execute(sql) >>>
Now we would like to populate the TEST table with some test data. So we'll create a list of parameter value tuples and send that list to the executemany() method, along with an INSERT statement:
>>> sql = "INSERT INTO TEST VALUES(?, ?, ?)" >>> plist = [('%03d' % i, 'TEST%03d' % i, 'Test record %s.' % i) ... for i in range(5)] >>> plist [('001', 'TEST001', 'Test record 1.'), ('002', 'TEST002', 'Test record 2.'), ('003', 'TEST003', 'Test record 3.'), ('004', 'TEST004', 'Test record 4.')] >>> curs.executemany(sql, plist) 4 >>> curs.execute('Select * from TEST') >>> curs.fetchall() [('001', 'TEST001', 'Test record 1.'), ('002', 'TEST002', 'Test record 2.'), ('003', 'TEST003', 'Test record 3.'), ('004', 'TEST004', 'Test record 4.')] >>>
The DB-API standard does not define a return value for executemany(), but as you can see in the previous example, the DB2 interface returns a count of the number of successful executions, or zero if there was a problem requiring a transaction rollback.
Transactions
A transaction combines a series of commands such that either all of them are executed or none of them are executed (and the database is returned to its original state). To support this capability, a connection object has two methods: commit() makes permanent any pending changes; rollback() discards any pending changes. A transactions starts implicitly at cursor creation time and after each call to
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 16 of 26
ibm.com/developerWorks
developerWorks
commit() or rollback(). A transaction in one connection is independent of transactions in other connections. Cursors are associated with a particular connection. Multiple cursors associated with the same connection are all part of the same transaction. Therefore, changes made in one cursor are visible to all other cursors that share the same connection. Transactions can span multiple calls to execute(). The basic idea is to create a connection, create one or more cursors for that connection, then execute one or more SQL statements using the cursors. Depending on the results of those commands, a decision will be made to either commit the transaction or roll back any changes.
Transaction example
Here is a simple example of the transaction process:
>>> import DB2 >>> conn = DB2.connect(dsn='sample', uid='db2inst1', ... pwd='******', autocommit=False) >>> curs = conn.cursor() >>> sql = 'UPDATE ORG SET DEPTNAME = ? WHERE DEPTNUMB = ?' >>> curs.execute(sql, ('Main Office', 10)) 1 >>> sql = 'UPDATE ORG SET LOCATION = ? WHERE DEPTNAME = ?' >>> curs.execute(sql, ('St. Louis', 'Plains')) 1 >>> curs.execute('SELECT * FROM ORG') >>> curs.fetchall() [(10, 'Main Office', 160, 'Corporate', 'New York'), (15, 'New England', 50, 'Eastern', 'Boston'), (20, 'Mid Atlantic', 10, 'Eastern', 'Washington'), (38, 'South Atlantic', 30, 'Eastern', 'Atlanta'), (42, 'Great Lakes', 100, 'Midwest', 'Chicago'), (51, 'Plains', 140, 'Midwest', 'St. Louis'), (66, 'Pacific', 270, 'Western', 'San Francisco'), (84, 'Mountain', 290, 'Western', 'Denver')] >>> conn.rollback() >>> curs.execute('SELECT * FROM ORG') >>> curs.fetchall() [(10, 'Head Office', 160, 'Corporate', 'New York'), (15, 'New England', 50, 'Eastern', 'Boston'), (20, 'Mid Atlantic', 10, 'Eastern', 'Washington'), (38, 'South Atlantic', 30, 'Eastern', 'Atlanta'), (42, 'Great Lakes', 100, 'Midwest', 'Chicago'), (51, 'Plains', 140, 'Midwest', 'Dallas'), (66, 'Pacific', 270, 'Western', 'San Francisco'), (84, 'Mountain', 290, 'Western', 'Denver')] >>>
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 17 of 26
developerWorks
ibm.com/developerWorks
In the same situation, the cursor's fetchone() method will return None:
>>> curs.execute('SELECT * FROM STAFF WHERE 1=0') >>> row = curs.fetchone() >>> print row None >>>
Case sensitivity
Case sensitivity can sometimes trip up newcomers. For the record, Python is case sensitive while SQL, for the most part, is not. Note that, in DB2, quoted identifiers (such as table names) are also case sensitive, as demonstrated in the following example:
>>> curs.execute('SELECT * FROM STAFF') # Uppercase works fine. >>> curs.execute('SELECT * FROM staff') # As does lowercase. >>> curs.execute('SELECT * FROM "STAFF"') # This quoted name works. >>> curs.execute('SELECT * FROM "staff"') # But lowercase does not. Traceback (most recent call last): File "<input>", line 1, in ? File "/home/pobrien/Code/PyDB2/DB2.py", line 311, in execute ret = self._cs.execute(stmt) error: SQLSTATE : 42S02, NATIVE ERROR CODE : -204 [IBM][CLI Driver][DB2/LINUX] SQL0204N SQLSTATE=42704 >>> "DB2INST1.staff" is an undefined name.
ibm.com/developerWorks
developerWorks
The db2util module provides a few utilities that make it easier to work with the DB2 interface. The entire source code is provided below. The rest of this section highlights the most useful functions and show examples of their use.
"""Utilities for use with DB2 and the Python DB2 interface.""" __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>" __cvsid__ = "$Id: db2util.py,v 1.2 2002/12/04 00:38:09 pobrien Exp $" __revision__ = "$Revision: 1.2 $"[11:-2] import DB2 SQLTYPES = ( 'SQL_BIGINT', 'SQL_BINARY', 'SQL_BLOB', 'SQL_BLOB_LOCATOR', 'SQL_CHAR', 'SQL_CLOB', 'SQL_CLOB_LOCATOR', 'SQL_TYPE_DATE', 'SQL_DBCLOB', 'SQL_DBCLOB_LOCATOR', 'SQL_DECIMAL', 'SQL_DOUBLE', 'SQL_FLOAT', 'SQL_GRAPHIC', 'SQL_INTEGER', 'SQL_LONGVARCHAR', 'SQL_LONGVARBINARY', 'SQL_LONGVARGRAPHIC', 'SQL_NUMERIC', 'SQL_REAL', 'SQL_SMALLINT', 'SQL_TYPE_TIME', 'SQL_TYPE_TIMESTAMP', 'SQL_VARCHAR', 'SQL_VARBINARY', 'SQL_VARGRAPHIC', ) BINARYTYPES = ( 'SQL_BLOB', 'SQL_BLOB_LOCATOR', 'SQL_CLOB', 'SQL_CLOB_LOCATOR', 'SQL_DBCLOB', 'SQL_DBCLOB_LOCATOR', 'SQL_GRAPHIC', 'SQL_LONGVARBINARY', 'SQL_LONGVARGRAPHIC', 'SQL_VARBINARY', 'SQL_VARGRAPHIC' ) def connect(dsn='sample', uid='db2inst1', pwd='ibmdb2', autocommit=True, connecttype=1): """Return connection to DB2.""" conn = DB2.connect(dsn, uid, pwd, autocommit, connecttype) return conn def fp(cursor, sep=' ', null=''): """Fetch and print all rows returned by cursor.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 19 of 26
developerWorks
ibm.com/developerWorks
cursor is a database cursor sep is the column separator (default is one space) null is the representation for a NULL value (default is an empty string) """ rows = cursor.fetchall() cprint(cursor, rows, sep, null) def cprint(cursor, rows, sep=' ', null=None): """Print rows returned by cursor in a columnar format. cursor is a database cursor rows is a list of tuples returned by cursor.fetch* sep is the column separator (default is one space) null is the representation for a NULL value (default is None) """ columns = cursor.description2 if not columns: return '*** NO QUERY WAS EXECUTED ***' headers = getheaders(columns, sep) # Format the rows. dataformats = getdataformats(columns) textformats = gettextformats(columns) rows = [formatrow(row, dataformats, textformats, sep, null) for row in rows] # Print the final formatted text. print "\n".join(headers + rows) def getheaders(columns, sep): """Return list of headers for columnar display.""" nameheader = getnameheader(columns, sep) # Dashes will separate the names from the values. dashheader = getdashheader(columns, sep) headers = [nameheader, dashheader] return headers def getnameheader(columns, sep): """Return name header.""" names = getnames(columns) textformats = gettextformats(columns) textformat = sep.join(textformats) header = textformat % tuple(names) return header def getdashheader(columns, sep): """Return dash header.""" dashes = getdashes(columns) textformats = gettextformats(columns) textformat = sep.join(textformats) header = textformat % tuple(dashes) return header def getnames(columns): """Return list of names for columns""" names = [column[0] for column in columns] return names def getdashes(columns): """Return list of dashes for columnar display.""" sizes = getdisplaysizes(columns) dashes = ['-' * size for size in sizes] return dashes def getdisplaysizes(columns): """Return list of display sizes required for columns.""" sizes = [getdisplaysize(column) for column in columns] return sizes def getdisplaysize(column): """Return display size required for column."""
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 20 of 26
ibm.com/developerWorks
developerWorks
name, type, displaysize, internalsize, precision, scale, nullokay = column size = max(len(name), displaysize) if type in BINARYTYPES: if type in ('SQL_DBCLOB', 'SQL_DBCLOB_LOCATOR'): size = max(len(name), len('<DBCLOB>')) else: size = max(len(name), len('<?LOB>')) return size def gettextformats(columns): """Return list of text format strings for columns.""" sizes = getdisplaysizes(columns) textformats = ['%%-%ss' % size for size in sizes] return textformats def getdataformats(columns): """Return list of data format strings for columns.""" dataformats = [getdataformat(column) for column in columns] return dataformats def getdataformat(column): """Return data format string for column.""" name, type, displaysize, internalsize, precision, scale, nullokay = column size = getdisplaysize(column) if type in ('SQL_DECIMAL', 'SQL_DOUBLE', 'SQL_FLOAT', 'SQL_NUMERIC', 'SQL_REAL'): format = '%%%s.%sf' % (size, scale) elif type in ('SQL_BIGINT', 'SQL_INTEGER', 'SQL_SMALLINT'): format = '%%%si' % (size) elif type in BINARYTYPES: format = '%%-%sr' % (size) else: format = '%%-%ss' % (size) return format def formatrow(row, dataformats, textformats, sep, null=None): """Return row as formatted string, taking into account NULL values.""" row = list(row) formats = [] for n in range(len(row)): if row[n] is None: if null is not None: row[n] = null formats.append(textformats[n]) else: formats.append(dataformats[n]) format = sep.join(formats) row = format % tuple(row) return row
Connecting
The db2util module provides a connect() function that parallels the connect() constructor in the DB2 module. The only difference is that the db2util version provides keyword arguments with useful default values, which can be quite helpful in a Python shell such as IDLE or PyCrust. Also, since a connection is the entry point to all the other DB2 functionality, you have access to everything you need by simply importing the db2util module. Here is the code for the connect() function:
def connect(dsn='sample', uid='db2inst1', pwd='ibmdb2', autocommit=True, connecttype=1):
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 21 of 26
developerWorks
ibm.com/developerWorks
"""Return connection to DB2.""" conn = DB2.connect(dsn, uid, pwd, autocommit, connecttype) return conn
Using the db2util connect() function is almost identical to the DB2 module's version:
>>> >>> >>> >>> >>> from PyDB2 import db2util conn = db2util.connect(pwd='******') curs = conn.cursor() curs.execute('SELECT * FROM STAFF')
Here are the results of running fp() with a few different queries:
>>> from PyDB2 import db2util >>> conn = db2util.connect(pwd='******') >>> curs = conn.cursor() >>> from PyDB2.db2util import fp >>> curs.execute('SELECT * FROM ORG') >>> fp(curs) DEPTNUMB DEPTNAME MANAGER DIVISION LOCATION -------- -------------- ------- ---------- ------------10 Head Office 160 Corporate New York 15 New England 50 Eastern Boston 20 Mid Atlantic 10 Eastern Washington 38 South Atlantic 30 Eastern Atlanta 42 Great Lakes 100 Midwest Chicago 51 Plains 140 Midwest Dallas 66 Pacific 270 Western San Francisco 84 Mountain 290 Western Denver >>> curs.execute('SELECT * FROM STAFF WHERE YEARS > 9') >>> fp(curs) ID NAME DEPT JOB YEARS SALARY COMM
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 22 of 26
ibm.com/developerWorks
developerWorks
--------- ------ ----- ------ --------- --------Hanes 15 Mgr 10 20659.80 Lu 10 Mgr 10 20010.00 Jones 10 Mgr 12 21234.00 Quill 84 Mgr 10 19818.00 Graham 66 Sales 13 21000.00 200.30
Cursor printing
The fp() function described in the previous section had very few lines of source code because it relied heavily on the functionality provided by the cprint() function. The cprint() function also expects to receive a cursor object that has already executed a SELECT query, but it also requires the rows returned by one of the fetch methods. Like fp(), you may supply a separator and NULL representation. Looking at the source code reveals the use of the cursor.description2 to determine the column formatting for the result set:
def cprint(cursor, rows, sep=' ', null=None): """Print rows returned by cursor in a columnar format. cursor is a database cursor rows is a list of tuples returned by cursor.fetch* sep is the column separator (default is one space) null is the representation for a NULL value (default is None) """ columns = cursor.description2 if not columns: return '*** NO QUERY WAS EXECUTED ***' headers = getheaders(columns, sep) # Format the rows. dataformats = getdataformats(columns) textformats = gettextformats(columns) rows = [formatrow(row, dataformats, textformats, sep, null) for row in rows] # Print the final formatted text. print "\n".join(headers + rows)
Here is one example of cprint() where we supply a different column separator and NULL representation:
>>> curs.execute('SELECT * FROM STAFF WHERE YEARS > 9') >>> rows = curs.fetchall() >>> db2util.cprint(curs, rows, sep=' | ', null='*********') ID | NAME | DEPT | JOB | YEARS | SALARY | COMM ------ | --------- | ------ | ----- | ------ | --------- | --------50 | Hanes | 15 | Mgr | 10 | 20659.80 | ********* 210 | Lu | 10 | Mgr | 10 | 20010.00 | ********* 260 | Jones | 10 | Mgr | 12 | 21234.00 | ********* 290 | Quill | 84 | Mgr | 10 | 19818.00 | ********* 310 | Graham | 66 | Sales | 13 | 21000.00 | 200.30 >>>
Looking at the source code for cprint(), you can see that it calls upon several other functions defined in the db2util module. While we won't describe the rest of
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved. Trademarks Page 23 of 26
developerWorks
ibm.com/developerWorks
them in this tutorial, their purpose is readily apparent and the code should be relatively easy to follow. These functions illustrate the use of the DB2 module and provide a solid foundation to build upon. For example, the db2util module could be used in the creation of a graphical query tool.
Section 5. Summary
DB2 and Python summary
This tutorial walked you through the steps involved in accessing DB2 databases using the Python programming language. Specifically, we covered techniques dealing with: Options for connecting to a DB2 database Creating connections and cursors Executing SELECT, INSERT, and UPDATE queries and other SQL statements Interacting with and displaying result sets Autocommiting vs. explicitly committing or canceling transactions Utilities for accessing and displaying DB2 data I hope this tutorial has demonstrated how simple it is to work with DB2 using the Python DB2 module. If you followed all the examples, you should be well on your way to productively combining these two great technologies to build applications that leverage the power and performance of the DB2 DBMS. I'd like to thank Man-Yong (Bryan) Lee, author of the Python DB2 module, for his assistance and for nurturing the DB2 module over the past few years. During the writing of this tutorial, we decided to move the DB2 module to SourceForge, in order to make it more accessible to others. We are happy to announce that the original interface files, plus the new db2util module, are now available at the PyDB2 project. We welcome any developers who would like to improve and extend the use of Python with DB2.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 24 of 26
ibm.com/developerWorks
developerWorks
Resources
Learn For a thorough introduction to the power of Python, see the Python Tutorial by Guido van Rossum, the author of the Python programming language. The Python Database SIG contains links to additional documentation and a mailing list. The DB-API Spec defines the Python Database API Specification. For an overview of using Python and Perl with IBM DB2, see the IBM article The Camel and the Snake. Python Persistence is an article from IBM that discusses alternative persistence mechanisms. IBM's DB2 developer domain is a great place to look for additional DB2 resources for developers. Detailed information on db2sampl and the SAMPLE database is available at the DB2 Information Center. Stay current with developerWorks technical events and webcasts. Get products and technologies The PyDB2 Package contains the Python DB2 interface module and utilities. Project: PyDB2 contains additional information about the package. Build your next development project with IBM trial software, available for download directly from developerWorks. Discuss Participate in the discussion forum for this content.
developerWorks
ibm.com/developerWorks
a developer of the PythonCard wxPython application construction kit, and leader of the PyPerSyst team, which is working on several object persistence mechanisms for Python applications. His Python articles have been published by O'Reilly and IBM, and he has presented at the O'Reilly Open Source Convention. You can contact Patrick at pobrien@orbtech.com.
Using Python to access DB2 for Linux Copyright IBM Corporation 2002. All rights reserved.
Trademarks Page 26 of 26