1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
############################
Quick-start Guide / Tutorial
############################
This brief tutorial aims to get the reader started by demonstrating
elementary usage of KInterbasDB. It is not a comprehensive Python
Database API tutorial, nor is it comprehensive in its coverage of
anything else.
The numerous advanced features of KInterbasDB are covered in another
section of this documentation, which is not in a tutorial format, though it
is replete with examples.
Connecting to a Database
========================
**Example 1**
A database connection is typically established with code such as this:
.. sourcecode:: python
import kinterbasdb
# The server is named 'bison'; the database file is at '/temp/test.db'.
con = kinterbasdb.connect(dsn='bison:/temp/test.db', user='sysdba', password='pass')
# Or, equivalently:
con = kinterbasdb.connect(
host='bison', database='/temp/test.db',
user='sysdba', password='pass'
)
**Example 2**
Suppose we want to connect to the database in SQL Dialect 1 and specifying
UTF-8 as the character set of the connection:
.. sourcecode:: python
import kinterbasdb
con = kinterbasdb.connect(
dsn='bison:/temp/test.db',
user='sysdba', password='pass',
dialect=1, # necessary for all dialect 1 databases
charset='UTF8' # specify a character set for the connection
)
Executing SQL Statements
========================
For this section, suppose we have a table defined and populated by the
following SQL code:
.. sourcecode:: sql
create table languages
(
name varchar(20),
year_released integer
);
insert into languages (name, year_released) values ('C', 1972);
insert into languages (name, year_released) values ('Python', 1991);
**Example 1**
This example shows the *simplest* way to print the entire contents of
the `languages` table:
.. sourcecode:: python
import kinterbasdb
con = kinterbasdb.connect(dsn='/temp/test.db', user='sysdba', password='masterkey')
# Create a Cursor object that operates in the context of Connection con:
cur = con.cursor()
# Execute the SELECT statement:
cur.execute("select * from languages order by year_released")
# Retrieve all rows as a sequence and print that sequence:
print cur.fetchall()
Sample output:
.. sourcecode:: python
[('C', 1972), ('Python', 1991)]
**Example 2**
Here's another trivial example that demonstrates various ways of
fetching a single row at a time from a `SELECT`-cursor:
.. sourcecode:: python
import kinterbasdb
con = kinterbasdb.connect(dsn='/temp/test.db', user='sysdba', password='masterkey')
cur = con.cursor()
SELECT = "select name, year_released from languages order by year_released"
# 1. Iterate over the rows available from the cursor, unpacking the
# resulting sequences to yield their elements (name, year_released):
cur.execute(SELECT)
for (name, year_released) in cur:
print '%s has been publicly available since %d.' % (name, year_released)
# 2. Equivalently:
cur.execute(SELECT)
for row in cur:
print '%s has been publicly available since %d.' % (row[0], row[1])
# 3. Using mapping-iteration rather than sequence-iteration:
cur.execute(SELECT)
for row in cur.itermap():
print '%(name)s has been publicly available since %(year_released)d.' % row
Sample output:
.. sourcecode:: python
C has been publicly available since 1972.
Python has been publicly available since 1991.
C has been publicly available since 1972.
Python has been publicly available since 1991.
C has been publicly available since 1972.
Python has been publicly available since 1991.
**Example 3**
The following program is a simplistic table printer (applied in this
example to `languages`):
.. sourcecode:: python
import kinterbasdb as k
TABLE_NAME = 'languages'
SELECT = 'select * from %s order by year_released' % TABLE_NAME
con = k.connect(dsn='/temp/test.db', user='sysdba', password='masterkey')
cur = con.cursor()
cur.execute(SELECT)
# Print a header.
for fieldDesc in cur.description:
print fieldDesc[k.DESCRIPTION_NAME].ljust(fieldDesc[k.DESCRIPTION_DISPLAY_SIZE]) ,
print # Finish the header with a newline.
print '-' * 78
# For each row, print the value of each field left-justified within
# the maximum possible width of that field.
fieldIndices = range(len(cur.description))
for row in cur:
for fieldIndex in fieldIndices:
fieldValue = str(row[fieldIndex])
fieldMaxWidth = cur.description[fieldIndex][k.DESCRIPTION_DISPLAY_SIZE]
print fieldValue.ljust(fieldMaxWidth) ,
print # Finish the row with a newline.
Sample output:
.. sourcecode:: python
NAME YEAR_RELEASED
------------------------------------------------------------------------------
C 1972
Python 1991
**Example 4**
Let's insert more languages:
.. sourcecode:: python
import kinterbasdb
con = kinterbasdb.connect(dsn='/temp/test.db', user='sysdba', password='masterkey')
cur = con.cursor()
newLanguages = [
('Lisp', 1958),
('Dylan', 1995),
]
cur.executemany("insert into languages (name, year_released) values (?, ?)",
newLanguages
)
# The changes will not be saved unless the transaction is committed explicitly:
con.commit()
Note the use of a *parameterized* SQL statement above. When dealing
with repetitive statements, this is much faster and less error-prone
than assembling each SQL statement manually. (You can read more about
parameterized SQL statements in the section on `Prepared Statements`.)
After running Example 4, the table printer from Example 3 would print:
.. sourcecode:: python
NAME YEAR_RELEASED
------------------------------------------------------------------------------
Lisp 1958
C 1972
Python 1991
Dylan 1995
Calling Stored Procedures
=========================
Firebird supports stored procedures written in a proprietary procedural
SQL language. Firebird stored procedures can have *input* parameters and/or
*output* parameters. Some databases support *input/output* parameters,
where the same parameter is used for both input and output; Firebird does
not support this.
It is important to distinguish between procedures that *return a
result set* and procedures that *populate and return their output
parameters exactly once*. Conceptually, the latter "return their
output parameters" like a Python function, whereas the former "yield
result rows" like a Python generator.
Firebird's *server-side* procedural SQL syntax makes no such distinction,
but *client-side* SQL code (and C API code) must. A result set is
retrieved from a stored procedure by `SELECT`ing from the procedure,
whereas output parameters are retrieved with an `EXECUTE PROCEDURE`
statement.
To *retrieve a result set* from a stored procedure with KInterbasDB,
use code such as this:
.. sourcecode:: python
cur.execute("select output1, output2 from the_proc(?, ?)", (input1, input2))
# Ordinary fetch code here, such as:
for row in cur:
... # process row
con.commit() # If the procedure had any side effects, commit them.
To *execute* a stored procedure and *access its output parameters*,
use code such as this:
.. sourcecode:: python
cur.callproc("the_proc", (input1, input2))
# If there are output parameters, retrieve them as though they were the
# first row of a result set. For example:
outputParams = cur.fetchone()
con.commit() # If the procedure had any side effects, commit them.
This latter is not very elegant; it would be preferable to access the
procedure's output parameters as the return value of
`Cursor.callproc()`. The Python DB API specification requires the
current behavior, however.
|