1 \section{Database classes overview
}\label{odbcoverview
}
3 Following is a detailed overview of how to use the wxWidgets ODBC classes -
\helpref{wxDb
}{wxdb
}
4 and
\helpref{wxDbTable
}{wxdbtable
} and their associated functions. These are
5 the ODBC classes donated by Remstar International, and are collectively
6 referred to herein as the wxODBC classes.
8 \subsection{wxDb/wxDbTable wxODBC Overview
}\label{wxodbcoverview
}
10 Classes:
\helpref{wxDb
}{wxdb
},
\helpref{wxDbTable
}{wxdbtable
}
12 The wxODBC classes were designed for database independence. Although SQL and
13 ODBC both have standards which define the minimum requirements they must
14 support to be in compliance with specifications, different database vendors
15 may implement things slightly differently. One example of this is that Oracle
16 requires all user names for the datasources to be supplied in uppercase
17 characters. In situations like this, the wxODBC classes have been written
18 to make this transparent to the programmer when using functions that require
19 database-specific syntax.
21 Currently several major databases, along with other widely used databases,
22 have been tested and supported through the wxODBC classes. The list of
23 supported databases is certain to grow as more users start implementing
24 software with these classes, but at the time of the writing of this
document,
25 users have successfully used the classes with the following datasources:
27 \begin{itemize
}\itemsep=
0pt
33 \item MS SQL Server (v7 - minimal testing)
34 \item MS Access (
97,
2000,
2002, and
2003)
35 \item MySQL (
2.x and
3.5 - use the
2.5x drivers though)
36 \item Oracle (v7, v8, v8i)
39 \item Sybase (ASA and ASE)
44 An up-to-date list can be obtained by looking in the comments of the function
45 \helpref{wxDb::Dbms
}{wxdbdbms
} in db.cpp, or in the enumerated type
46 \helpref{wxDBMS
}{wxdbenumeratedtypes
} in db.h.
48 **dBase is not truly an ODBC datasource, but there are drivers which can
49 emulate much of the functionality of an ODBC connection to a dBase table.
50 See the
\helpref{wxODBC Known Issues
}{wxodbcknownissues
} section of this
54 \subsection{wxODBC Where To Start
}\label{wxodbcwheretostart
}
56 First, if you are not familiar with SQL and ODBC, go to your local bookstore
57 and pick up a good book on each. This documentation is not meant to teach
58 you many details about SQL or ODBC, though you may learn some just from
59 immersion in the subject.
61 If you have worked with non-SQL/ODBC datasources before, there are some
62 things you will need to un-learn. First some terminology as these phrases will
63 be used heavily in this section of the manual.
65 \begin{twocollist
}\itemsep=
0pt
66 \twocolitem{Datasource
}{(usually a database) that contains the data that will be
67 accessed by the wxODBC classes.
}
68 \twocolitem{Data table
}{The section of the datasource that contains the rows and
70 \twocolitem{ODBC driver
}{The middle-ware software that interprets the ODBC
71 commands sent by your application and converts them to the SQL format expected
72 by the target datasource.
}
73 \twocolitem{Datasource connection
}{An open pipe between your application and
74 the ODBC driver which in turn has a connection to the target datasource.
75 Datasource connections can have a virtually unlimited number of wxDbTable
76 instances using the same connect (dependent on the ODBC driver). A separate
77 connection is not needed for each table (the exception is for isolating
78 commits/rollbacks on different tables from affecting more than the desired
79 table. See the class documentation on
80 \helpref{wxDb::CommitTrans
}{wxdbcommittrans
} and
81 \helpref{wxDb::RollbackTrans
}{wxdbrollbacktrans
}.)
}
82 \twocolitem{Rows
}{Similar to records in old relational databases, a row is a
83 collection of one instance of each column of the data table that are all
84 associated with each other.
}
85 \twocolitem{Columns
}{Individual fields associated with each row of a data
87 \twocolitem{Query
}{Request from the client to the datasource asking for
88 the data that matches the requirements specified in the users request. When
89 a query is performed, the datasource performs the lookup of the rows with
90 satisfy the query, and creates a result set.
}
91 \twocolitem{Result set
}{The data which matches the requirements specified
92 in a query sent to the datasource. Dependent on drivers, a result set
93 typically remains at the datasource (no data is transmitted to the ODBC driver)
94 until the client actually instructs the ODBC driver to retrieve it.
}
95 \twocolitem{Cursor
}{A logical pointer into the result set that a query
96 generates, indicating the next record that will be returned to the client
97 when a request for the next record is made.
}
98 \twocolitem{Scrolling cursors
}{Scrolling refers to the movement of cursors
99 through the result set. Cursors can always scroll forward sequentially in
100 the result set (FORWARD ONLY scrolling cursors). With Forward only scrolling
101 cursors, once a row in the result set has been returned to the ODBC driver
102 and on to the client, there is no way to have the cursor move backward in
103 the result set to look at the row that is previous to the current row in
104 the result set. If BACKWARD scrolling cursors are supported by both the
105 ODBC driver and the datasource that are being used, then backward
106 scrolling cursor functions may be used (
107 \helpref{wxDbTable::GetPrev
}{wxdbtablegetprev
},
108 \helpref{wxDbTable::GetFirst
}{wxdbtablegetfirst
}, and
109 \helpref{wxDbTable::GetLast
}{wxdbtablegetlast
}). If the datasource or the
110 ODBC driver only support forward scrolling cursors, your program and logic
111 must take this in to account.
}
112 \twocolitem{Commit/Rollback
}{Commit will physically save
113 insertions/deletions/updates, while rollback basically does an undo of
114 everything done against the datasource connection that has not been
115 previously committed. Note that Commit and Rollbacks are done on a
116 connection, not on individual tables. All tables which use a shared
117 connection to the datasource are all committed/rolled back at the same
119 \helpref{wxDb::CommitTrans
}{wxdbcommittrans
} or
120 \helpref{wxDb::RollbackTrans
}{wxdbrollbacktrans
} is made.
}
121 \twocolitem{Index
}{Indexes are datasource-maintained lookup structures
122 that allow the datasource to quickly locate data rows based on the values
123 of certain columns. Without indexes, the datasource would need to do a
124 sequential search of a table every time a query request is made. Proper
125 unique key index construction can make datasource queries nearly instantaneous.
}
128 Before you are able to read data from a data table in a datasource, you must
129 have a connection to the datasource. Each datasource connection may be used
130 to open multiple tables all on the same connection (number of tables open are
131 dependent on the driver, datasource configuration and the amount of memory on
132 the client workstation). Multiple connections can be opened to the same
133 datasource by the same client (number of concurrent connections is dependent
134 on the driver and datasource configuration).
136 When a query is performed, the client passes the query to the ODBC driver,
137 and the driver then translates it and passes it along to the datasource. The
138 database engine (in most cases - exceptions are text and dBase files) running
139 on the machine hosting the database does all the work of performing the search
140 for the requested data. The client simply waits for a status to come back
141 through the ODBC driver from the datasource.
143 Depending on the ODBC driver, the result set either remains "queued" on the
144 database server side, or is transferred to the machine that the driver is
145 queued on. The client does not receive this data. The client must request
146 some or all of the result set to be returned before any data rows are
147 returned to the client application.
149 Result sets do not need to include all columns of every row matching the
150 query. In fact, result sets can actually be joinings of columns from two
151 or more data tables, may have derived column values, or calculated values
154 For each result set, a cursor is maintained (typically by the database)
155 which keeps track of where in the result set the user currently is.
156 Depending on the database, ODBC driver, and how you configured the
157 wxWidgets ODBC settings in setup.h (see
\helpref{wxODBC - Compiling
}{wxodbccompiling
}), cursors can be
158 either forward or backward scrolling. At a minimum, cursors must scroll
159 forward. For example, if a query resulted in a result set with
100 rows,
160 as the data is read by the client application, it will read row
1, then
2,
161 then
3, etc. With forward only cursors, once the cursor has moved to
162 the next row, the previous row cannot be accessed again without re-querying
163 the datasource for the result set over again. Backward scrolling cursors
164 allow you to request the previous row from the result set, actually
165 scrolling the cursor backward.
167 Backward scrolling cursors are not supported on all database/driver
168 combinations. For this reason, forward-only cursors are the default in
169 the wxODBC classes. If your datasource does support backward scrolling
170 cursors and you wish to use them, make the appropriate changes in setup.h
171 to enable them (see
\helpref{wxODBC - Compiling
}{wxodbccompiling
}). For greatest portability between
172 datasources, writing your program in such a way that it only requires
173 forward scrolling cursors is your best bet. On the other hand, if you are
174 focusing on using only datasources that support backward scrolling cursors,
175 potentially large performance benefits can be gained from using them.
177 There is a limit to the number of cursors that can be open on each connection
178 to the datasource, and usually a maximum number of cursors for the datasource
179 itself. This is all dependent on the database. Each connection that is
180 opened (each instance of a wxDb) opens a minimum of
5 cursors on creation
181 that are required for things such as updates/deletions/rollbacks/queries.
182 Cursors are a limited resource, so use care in creating large numbers of
185 Additional cursors can be created if necessary with the
186 \helpref{wxDbTable::GetNewCursor
}{wxdbtablegetnewcursor
} function. One example
187 use for additional cursors is to track multiple scroll points in result
188 sets. By creating a new cursor, a program could request a second result set
189 from the datasource while still maintaining the original cursor position in
190 the first result set.
192 Different than non-SQL/ODBC datasources, when a program performs an
193 insertion, deletion, or update (or other SQL functions like altering
194 tables, etc) through ODBC, the program must issue a "commit" to the
195 datasource to tell the datasource that the action(s) it has been told to
196 perform are to be recorded as permanent. Until a commit is performed,
197 any other programs that query the datasource will not see the changes that
198 have been made (although there are databases that can be configured to
199 auto-commit). NOTE: With most datasources, until the commit is
200 performed, any cursor that is open on that same datasource connection
201 will be able to see the changes that are uncommitted. Check your
202 database's documentation/configuration to verify this before relying on it
205 A rollback is basically an UNDO command on the datasource connection. When
206 a rollback is issued, the datasource will flush all commands it has been told
207 to do since the last commit that was performed.
209 NOTE: Commits/Rollbacks are done on datasource connections (wxDb instances)
210 not on the wxDbTable instances. This means that if more than one table
211 shares the same connection, and a commit or rollback is done on that
212 connection, all pending changes for ALL tables using that connection are
213 committed/rolled back.
215 \subsection{wxODBC - Configuring your system for ODBC use
}\label{wxodbcconfiguringyoursystem
}
217 Before you are able to access a datasource, you must have installed and
218 configured an ODBC driver. Doing this is system specific, so it will not be
219 covered in detail here. But here are a few details to get you started.
221 Most database vendors provide at least a minimal ODBC driver with their
222 database product. In practice, many of these drivers have proven to be slow
223 and/or incomplete. Rumour has it that this is because the vendors do not want
224 you using the ODBC interface to their products; they want you to use their
225 applications to access the data.
227 Whatever the reason, for database-intensive applications, you may want to
228 consider using a third-party ODBC driver for your needs. One example of a
229 third-party set of ODBC drivers that has been heavily tested and used is
230 Rogue Wave's drivers. Rogue Wave has drivers available for many different
231 platforms and databases.
233 Under Microsoft Windows, install the ODBC driver you are planning to use. You
234 will then use the ODBC Administrator in the Control Panel to configure an
235 instance of the driver for your intended datasource. Note that with all
236 flavors of NT, this configuration can be set up as a System or User DSN
237 (datasource name). Configuring it as a system resource will make it
238 available to all users (if you are logged in as 'administrator'), otherwise
239 the datasource will only be available to the user who configured the DSN.
241 Under Unix, iODBC is used for implementation of the ODBC API. To compile the
242 wxODBC classes, you must first obtain iODBC from
\urlref{http://www.iodbc.org
}{www.iodbc.org
} and install it.
243 (Note: wxWidgets currently includes a version of iODBC.) Then you must create the file "~/.odbc.ini" (or optionally create
244 "/etc/odbc.ini" for access for all users on the system). This file contains
245 the settings for your system/datasource. Below is an example section of a
246 odbc.ini file for use with the "samples/db" sample program using MySQL:
252 Driver = /usr/local/lib/libmyodbc.so
254 SERVER =
192.168.1.13
260 \subsection{wxODBC - Compiling
}\label{wxodbccompiling
}
262 The wxWidgets setup.h file has several settings in it pertaining to compiling
265 \begin{twocollist
}\itemsep=
0pt
266 \twocolitem{wxUSE
\_ODBC}{This must be set to
1 in order for the compiler to
267 compile the wxODBC classes. Without setting this to
1, there will be no
268 access to any of the wxODBC classes. The default is
0.
}
269 \twocolitem{wxODBC
\_FWD\_ONLY\_CURSORS}{When a new database connection is
270 requested, this setting controls the default of whether the connection allows
271 only forward scrolling cursors, or forward and backward scrolling cursors
272 (see the section in "WHERE TO START" on cursors for more information on
273 cursors). This default can be overridden by passing a second parameter to
274 either the
\helpref{wxDbGetConnection
}{wxdbfunctions
} or
275 \helpref{wxDb constructor
}{wxdbctor
}. The default is
1.
}
276 \twocolitem{wxODBC
\_BACKWARD\_COMPATABILITY}{Between v2.0 and
2.2, massive
277 renaming efforts were done to the ODBC classes to get naming conventions
278 similar to those used throughout wxWidgets, as well as to preface all wxODBC
279 classes names and functions with a wxDb preface. Because this renaming would
280 affect applications written using the v2.0 names, this compile-time directive
281 was added to allow those programs written for v2.0 to still compile using the
282 old naming conventions. These deprecated names are all
{\tt\#
}define'd to their
283 corresponding new function names at the end of the db.cpp/dbtable.cpp source
284 files. These deprecated class/function names should not be used in future
285 development, as at some point in the future they will be removed. The default
289 {\it Under MS Windows
}
291 You are required to include the "odbc32.lib" provided by your compiler vendor
292 in the list of external libraries to be linked in. If using the makefiles
293 supplied with wxWidgets, this library should already be included for use with
294 makefile.b32, makefile.vc, and makefile.g95.
296 \normalbox{MORE TO COME
}
299 --with-odbc flag for configure
301 \normalbox{MORE TO COME
}
303 \subsection{wxODBC - Basic Step-By-Step Guide
}\label{wxodbcstepbystep
}
305 To use the classes in an application, there are eight basic steps:
307 \begin{itemize
}\itemsep=
0pt
308 \item Define datasource connection information
309 \item Get a datasource connection
310 \item Create table definition
313 \item Close the table
314 \item Close the datasource connection
315 \item Release the ODBC environment handle
318 Following each of these steps is detailed to explain the step, and to
319 hopefully mention as many of the pitfalls that beginning users fall in
320 to when first starting to use the classes. Throughout the steps, small
321 snippets of code are provided to show the syntax of performing the step. A
322 complete code snippet is provided at the end of this overview that shows a
323 complete working flow of all these steps (see
324 \helpref{wxODBC - Sample Code
}{wxodbcsamplecode1
}).
326 {\bf Define datasource connection information
}
328 To be able to connect to a datasource through the ODBC driver, a program must
329 supply a minimum of three pieces of information: Datasource name, User ID, and
330 Authorization string (password). A fourth piece of information, a default
331 directory indicating where the data file is stored, is required for Text and
332 dBase drivers for ODBC.
334 The wxWidgets data class wxDbConnectInf exists for holding all of these
335 values, plus some others that may be desired.
337 The 'Henv' member is the environment handle used to access memory for use by the
338 ODBC driver. Use of this member is described below in the "Getting a Connection
339 to the Datasource" section.
341 The 'Dsn' must exactly match the datasource name used to configure the ODBC
342 datasource (in the ODBC Administrator (MSW only) or in the .odbc.ini file).
344 The 'Uid' is the User ID that is to be used to log in to the datasource. This
345 User ID must already have been created and assigned rights within the
346 datasource to which you are connecting. The user that the connection is
347 establish by will determine what rights and privileges the datasource
348 connection will allow the program to have when using the connection that
349 this connection information was used to establish. Some datasources are
350 case sensitive for User IDs, and though the wxODBC classes attempt to hide
351 this from you by manipulating whatever data you pass in to match the
352 datasource's needs, it is always best to pass the 'Uid' in the case that
353 the datasource requires.
355 The 'AuthStr' is the password for the User ID specified in the 'Uid' member.
356 As with the 'Uid', some datasources are case sensitive (in fact most are).
357 The wxODBC classes do NOT try to manage the case of the 'AuthStr' at all.
358 It is passed verbatim to the datasource, so you must use the case that the
359 datasource is expecting.
361 The 'defaultDir' member is used with file based datasources (i.e. dBase,
362 FoxPro, text files). It contains a full path to the location where the
363 data table or file is located. When setting this value, use forward
364 slashes '/' rather than backslashes '\' to avoid compatibility differences
365 between ODBC drivers.
367 The other fields are currently unused. The intent of these fields are that
368 they will be used to write our own ODBC Administrator type program that will
369 work on both MSW and Un*x systems, regardless of the datasource. Very little
370 work has been done on this to date.
372 {\bf Get a Datasource Connection
}
374 There are two methods of establishing a connection to a datasource. You
375 may either manually create your own wxDb instance and open the connection,
376 or you may use the caching functions provided with the wxODBC classes to
377 create/maintain/delete the connections.
379 Regardless of which method you use, you must first have a fully populated
380 wxDbConnectInf object. In the wxDbConnectInf instance, provide a valid
381 Dns, Uid, and AuthStr (along with a 'defaultDir' if necessary). Before
382 using this though, you must allocate an environment handle to the 'Henv'
386 wxDbConnectInf DbConnectInf;
387 DbConnectInf.SetDsn("MyDSN");
388 DbConnectInf.SetUserID("MyUserName");
389 DbConnectInf.SetPassword("MyPassword");
390 DbConnectInf.SetDefaultDir("");
393 To allocate an environment handle for the ODBC connection to use, the
394 wxDbConnectInf class has a datasource independent method for creating
395 the necessary handle:
398 if (DbConnectInf.AllocHenv())
400 wxMessageBox("Unable to allocate an ODBC environment handle",
401 "DB CONNECTION ERROR", wxOK | wxICON_EXCLAMATION);
406 When the wxDbConnectInf::AllocHenv() function is called successfully, a
407 value of true will be returned. A value of false means allocation failed,
408 and the handle will be undefined.
410 A shorter form of doing the above steps is encapsulated into the
411 long form of the constructor for wxDbConnectInf.
414 wxDbConnectInf *DbConnectInf;
416 DbConnectInf = new wxDbConnectInf(NULL, "MyDSN", "MyUserName",
420 This shorthand form of initializing the constructor passes a NULL for the SQL
421 environment handle, telling the constructor to allocate a handle during
422 construction. This handle is also managed for the life of wxDbConnectInf
423 instance, and is freed automatically upon destruction of the instance.
425 Once the wxDbConnectInf instance is initialized, you are ready to
426 connect to the datasource.
428 To manually create datasource connections, you must create a wxDb
429 instance, and then open it.
432 wxDb *db = new wxDb(DbConnectInf->GetHenv());
434 opened = db->Open(DbConnectInf);
437 The first line does the house keeping needed to initialize all
438 the members of the wxDb class. The second line actually sends the request
439 to the ODBC driver to open a connection to its associated datasource using
440 the parameters supplied in the call to
\helpref{wxDb::Open
}{wxdbopen
}.
442 A more advanced form of opening a connection is to use the connection
443 caching functions that are included with the wxODBC classes. The caching
444 mechanisms perform the same functions as the manual approach to opening a
445 connection, but they also manage each connection they have created,
446 re-using them and cleaning them up when they are closed, without you
447 needing to do the coding.
449 To use the caching function
\helpref{wxDbGetConnection
}{wxdbfunctions
} to get
450 a connection to a datasource, simply call it with a single parameter of the
454 db = wxDbGetConnection(DbConnectInf);
457 The wxDb pointer that is returned is both initialized and opened. If
458 something failed in creating or opening the connection, the return value
459 from
\helpref{wxDbGetConnection
}{wxdbfunctions
} will be NULL.
461 The connection that is returned is either a new connection, or it is a
462 "free" connection from the cache of connections that the class maintains
463 that was no longer in use. Any wxDb instance created with a call to
464 \helpref{wxDbGetConnection
}{wxdbfunctions
} is recorded in a linked list of established
465 connections. When a program is finished with a connection, a call to
466 \helpref{wxDbFreeConnection
}{wxdbfunctions
} is made, and the datasource
467 connection will then be tagged as FREE, making it available for the next
468 call to
\helpref{wxDbGetConnection
}{wxdbfunctions
} that needs a connection
469 using the same connection information (Dsn, Uid, AuthStr). The cached
470 connections remain cached until a call to
\helpref{wxDbCloseConnections
}{wxdbfunctions
} is made,
471 at which time all cached connections are closed and deleted.
473 Besides the obvious advantage of using the single command caching routine to
474 obtain a datasource connection, using cached connections can be quite a
475 performance boost as well. Each time that a new connection is created
476 (not retrieved from the cache of free connections), the wxODBC classes
477 perform many queries against the datasource to determine the datasource's
478 datatypes and other fundamental behaviours. Depending on the hardware,
479 network bandwidth, and datasource speed, this can in some cases take a
480 few seconds to establish the new connection (with well-balanced systems,
481 it should only be a fraction of a second). Re-using already established
482 datasource connections rather than creating/deleting, creating/deleting
483 connections can be quite a time-saver.
485 Another time-saver is the "copy connection" features of both
486 \helpref{wxDb::Open
}{wxdbopen
} and
\helpref{wxDbGetConnection
}{wxdbfunctions
}.
487 If manually creating a wxDb instance and opening it, you must pass an existing
488 connection to the
\helpref{wxDb::Open
}{wxdbopen
} function yourself to gain the performance
489 benefit of copying existing connection settings. The
490 \helpref{wxDbGetConnection
}{wxdbfunctions
} function automatically does this
491 for you, checking the Dsn, Uid, and AuthStr parameters when you request
492 a connection for any existing connections that use those same settings.
493 If one is found,
\helpref{wxDbGetConnection
}{wxdbfunctions
} copies the datasource settings for
494 datatypes and other datasource specific information that was previously
495 queried, rather than re-querying the datasource for all those same settings.
497 One final note on creating a connection. When a connection is created, it
498 will default to only allowing cursor scrolling to be either forward only,
499 or both backward and forward scrolling. The default behavior is
500 determined by the setting
{\tt wxODBC
\_FWD\_ONLY\_CURSORS} in setup.h when you
501 compile the wxWidgets library. The library default is to only support
502 forward scrolling cursors only, though this can be overridden by parameters
503 for wxDb() constructor or the
\helpref{wxDbGetConnection
}{wxdbfunctions
}
504 function. All datasources and ODBC drivers must support forward scrolling
505 cursors. Many datasources support backward scrolling cursors, and many
506 ODBC drivers support backward scrolling cursors. Before planning on using
507 backward scrolling cursors, you must be certain that both your datasource
508 and ODBC driver fully support backward scrolling cursors. See the small
509 blurb about "Scrolling cursors" in the definitions at the beginning of
510 this overview, or other details of setting the cursor behavior in the wxDb
513 {\bf Create Table Definition
}
515 Data can be accessed in a datasource's tables directly through various
516 functions of the wxDb class (see
\helpref{wxDb::GetData
}{wxdbgetdata
}). But to make life much
517 simpler, the wxDbTable class encapsulates all of the SQL specific API calls
518 that would be necessary to do this, wrapping it in an intuitive class of APIs.
520 The first step in accessing data in a datasource's tables via the wxDbTable
521 class is to create a wxDbTable instance.
524 table = new wxDbTable(db, tableName, numTableColumns, "",
525 !wxDB_QUERY_ONLY, "");
528 When you create the instance, you indicate the previously established
529 datasource connection to be used to access the table, the name of the
530 primary table that is to be accessed with the datasource's tables, how many
531 columns of each row are going to be returned, the name of the view of the
532 table that will actually be used to query against (works with Oracle only
533 at this time), whether the data returned is for query purposes only, and
534 finally the path to the table, if different than the path specified when
535 connecting to the datasource.
537 Each of the above parameters are described in detail in the wxDbTable
538 class' description, but one special note here about the fifth
539 parameter - the queryOnly setting. If a wxDbTable instance is created as
540 {\tt wxDB
\_QUERY\_ONLY}, then no inserts/deletes/updates can be performed
541 using this instance of the wxDbTable. Any calls to
\helpref{wxDb::CommitTrans
}{wxdbcommittrans
}
542 or
\helpref{wxDb::RollbackTrans
}{wxdbrollbacktrans
} against the datasource
543 connection used by this wxDbTable instance are ignored by this instance. If
544 the wxDbTable instance is created with
{\tt !wxDB
\_QUERY\_ONLY} as shown above,
545 then all the cursors and other overhead associated with being able to
546 insert/update/delete data in the table are created, and thereby those
547 operations can then be performed against the associated table with this
550 If a table is to be accessed via a wxDbTable instance, and the table will
551 only be read from, not written to, there is a performance benefit (not as
552 many cursors need to be maintained/updated, hence speeding up access times),
553 as well as a resource savings due to fewer cursors being created for the
554 wxDbTable instance. Also, with some datasources, the number of
555 simultaneous cursors is limited.
557 When defining the columns to be retrievable by the wxDbTable instance, you
558 can specify anywhere from one column up to all columns in the table.
561 table->SetColDefs(
0, "FIRST_NAME", DB_DATA_TYPE_VARCHAR, FirstName,
562 SQL_C_WXCHAR, sizeof(FirstName), true, true);
563 table->SetColDefs(
1, "LAST_NAME", DB_DATA_TYPE_VARCHAR, LastName,
564 SQL_C_WXCHAR, sizeof(LastName), true, true);
567 Notice that column definitions start at index
0 and go up to one less than
568 the number of columns specified when the wxDbTable instance was created
569 (in this example, two columns - one with index
0, one with index
1).
571 The above lines of code "bind" the datasource columns specified to the
572 memory variables in the client application. So when the application
573 makes a call to
\helpref{wxDbTable::GetNext
}{wxdbtablegetnext
} (or any other function that retrieves
574 data from the result set), the variables that are bound to the columns will
575 have the column value stored into them. See the
576 \helpref{wxDbTable::SetColDefs
}{wxdbtablesetcoldefs
}
577 class documentation for more details on all the parameters for this function.
579 The bound memory variables have undefined data in them until a call to a
580 function that retrieves data from a result set is made
581 (e.g.
\helpref{wxDbTable::GetNext
}{wxdbtablegetnext
},
582 \helpref{wxDbTable::GetPrev
}{wxdbtablegetprev
}, etc). The variables are not
583 initialized to any data by the wxODBC classes, and they still contain
584 undefined data after a call to
\helpref{wxDbTable::Query
}{wxdbtablequery
}. Only
585 after a successful call to one of the ::GetXxxx() functions is made do the
586 variables contain valid data.
588 It is not necessary to define column definitions for columns whose data is
589 not going to be returned to the client. For example, if you want to query
590 the datasource for all users with a first name of 'GEORGE', but you only want
591 the list of last names associated with those rows (why return the FIRST
\_NAME
592 column every time when you already know it is 'GEORGE'), you would only have
593 needed to define one column above.
595 You may have as many wxDbTable instances accessing the same table using the
596 same wxDb instance as you desire. There is no limit imposed by the classes
597 on this. All datasources supported (so far) also have no limitations on this.
601 Opening the table is not technically doing anything with the datasource
602 itself. Calling
\helpref{wxDbTable::Open
}{wxdbtableopen
} simply does all the
603 housekeeping of checking that the specified table exists, that the current
604 connected user has at least SELECT privileges for accessing the table,
605 setting up the requisite cursors, binding columns and cursors, and
606 constructing the default INSERT statement that is used when a new row is
607 inserted into the table (non-wxDB
\_QUERY\_ONLY tables only).
612 // An error occurred opening (setting up) the table
616 The only reason that a call to
\helpref{wxDbTable::Open
}{wxdbtableopen
} is likely to fail is if the
617 user has insufficient privileges to even SELECT the table. Other problems
618 could occur, such as being unable to bind columns, but these other reason
619 point to some lack of resource (like memory). Any errors generated
620 internally in the
\helpref{wxDbTable::Open
}{wxdbtableopen
} function are logged to the error log
621 if SQL logging is turned on for the classes.
625 To use the table and the definitions that are now set up, we must first
626 define what data we want the datasource to collect in to a result set, tell
627 it where to get the data from, and in which sequence we want the data returned.
630 // the WHERE clause limits/specifies which rows in the table
631 // are to be returned in the result set
632 table->SetWhereClause("FIRST_NAME = 'GEORGE'");
634 // Result set will be sorted in ascending alphabetical
635 // order on the data in the 'LAST_NAME' column of each row
636 // If the same last name is in the table for two rows,
637 // sub-sort on the 'AGE' column
638 table->SetOrderByClause("LAST_NAME, AGE");
640 // No other tables (joins) are used for this query
641 table->SetFromClause("");
644 The above lines will be used to tell the datasource to return in the result
645 all the rows in the table whose column "FIRST
\_NAME" contains the name
646 'GEORGE' (note the required use of the single quote around the string
647 literal) and that the result set will return the rows sorted by ascending
648 last names (ascending is the default, and can be overridden with the
649 "DESC" keyword for datasources that support it - "LAST
\_NAME DESC").
651 Specifying a blank WHERE clause will result in the result set containing
652 all rows in the datasource.
654 Specifying a blank ORDERBY clause means that the datasource will return
655 the result set in whatever sequence it encounters rows which match the
656 selection criteria. What this sequence is can be hard to determine.
657 Typically it depends on the index that the datasource used to find the
658 rows which match the WHERE criteria. BEWARE - relying on the datasource
659 to return data in a certain sequence when you have not provided an ORDERBY
660 clause will eventually cause a problem for your program. Databases can be
661 tuned to be COST-based, SPEED-based, or some other basis for how it gets
662 your result set. In short, if you need your result set returned in a
663 specific sequence, ask for it that way by providing an ORDERBY clause.
665 Using an ORDERBY clause can be a performance hit, as the database must
666 sort the items before making the result set available to the client.
667 Creating efficient indexes that cause the data to be "found" in the correct
668 ORDERBY sequence can be a big performance benefit. Also, in the large
669 majority of cases, the database will be able to sort the records faster
670 than your application can read all the records in (unsorted) and then sort
671 them. Let the database do the work for you!
673 Notice in the example above, a column that is not included in the bound
674 data columns ('AGE') will be used to sub-sort the result set.
676 The FROM clause in this example is blanked, as we are not going to be
677 performing any table joins with this simple query. When the FROM clause
678 is blank, it is assumed that all columns referenced are coming from
679 the default table for the wxDbTable instance.
681 After the selection criteria have been specified, the program can now
682 ask the datasource to perform the search and create a result set that
686 // Instruct the datasource to perform a query based on the
687 // criteria specified above in the where/orderBy/from clauses.
690 // An error occurred performing the query
694 Typically, when an error occurs when calling
\helpref{wxDbTable::Query
}{wxdbtablequery
}, it is a
695 syntax problem in the WHERE clause that was specified. The exact SQL
696 (datasource-specific) reason for what caused the failure of
\helpref{wxDbTable::Query
}{wxdbtablequery
}
697 (and all other operations against the datasource can be found by
698 parsing the table's database connection's "errorList
[]" array member for
699 the stored text of the error.
701 When the
\helpref{wxDbTable::Query
}{wxdbtablequery
} returns true, the
702 database was able to successfully complete the requested query using the
703 provided criteria. This does not mean that there are any rows in the
704 result set, it just mean that the query was successful.
706 \normalbox{IMPORTANT: The result created by the call to
707 \helpref{wxDbTable::Query
}{wxdbtablequery
} can take one of two forms. It is
708 either a snapshot of the data at the exact moment that the database
709 determined the record matched the search criteria, or it is a pointer to
710 the row that matched the selection criteria. Which form of behavior is
711 datasource dependent. If it is a snapshot, the data may have changed
712 since the result set was constructed, so beware if your datasource
713 uses snapshots and call
\helpref{wxDbTable::Refresh
}{wxdbtablerefresh
}. Most larger brand databases
714 do not use snapshots, but it is important to mention so that your application
715 can handle it properly if your datasource does.
}
717 To retrieve the data, one of the data fetching routines must be used to
718 request a row from the result set, and to store the data from the result
719 set into the bound memory variables. After
\helpref{wxDbTable::Query
}{wxdbtablequery
}
720 has completed successfully, the default/current cursor is placed so it
721 is pointing just before the first record in the result set. If the
722 result set is empty (no rows matched the criteria), then any calls to
723 retrieve data from the result set will return false.
728 while (table->GetNext())
730 msg.Printf("Row #
%lu -- First Name : %s Last Name is %s",
731 table->GetRowNum(), FirstName, LastName);
732 wxMessageBox(msg, "Data", wxOK | wxICON_INFORMATION, NULL);
736 The sample code above will read the next record in the result set repeatedly
737 until the end of the result set has been reached. The first time that
738 \helpref{wxDbTable::GetNext
}{wxdbtablegetnext
} is called right after the successful
739 call to
\helpref{wxDbTable::Query
}{wxdbtablequery
}, it actually returns the first record
742 When
\helpref{wxDbTable::GetNext
}{wxdbtablegetnext
} is called and there are
743 no rows remaining in the result set after the current cursor position,
744 \helpref{wxDbTable::GetNext
}{wxdbtablegetnext
} (as well as all the other
745 wxDbTable::GetXxxxx() functions) will return false.
747 {\bf Close the table
}
749 When the program is done using a wxDbTable instance, it is as simple as
750 deleting the table pointer (or if declared statically, letting the
751 variable go out of scope). Typically the default destructor will take
752 care of all that is required for cleaning up the wxDbTable instance.
762 Deleting a wxDbTable instance releases all of its cursors, deletes the
763 column definitions and frees the SQL environment handles used by the
764 table (but not the environment handle used by the datasource connection
765 that the wxDbTable instance was using).
767 {\bf Close the datasource connection
}
769 After all tables that have been using a datasource connection have been
770 closed (this can be verified by calling
\helpref{wxDb::GetTableCount
}{wxdbgettablecount
}
771 and checking that it returns
0), then you may close the datasource
772 connection. The method of doing this is dependent on whether the
773 non-caching or caching method was used to obtain the datasource connection.
775 If the datasource connection was created manually (non-cached), closing the
776 connection is done like this:
787 If the program used the
\helpref{wxDbGetConnection
}{wxdbfunctions
} function to get a datasource
788 connection, the following is the code that should be used to free the
794 wxDbFreeConnection(db);
799 Note that the above code just frees the connection so that it can be
800 re-used on the next call the
\helpref{wxDbGetConnection
}{wxdbfunctions
}. To actually dispose
801 of the connection, releasing all of its resources (other than the
802 environment handle), do the following:
805 wxDbCloseConnections();
808 {\bf Release the ODBC environment handle
}
810 Once all of the connections that used the ODBC environment handle (in
811 this example it was stored in "DbConnectInf.Henv") have been closed, then
812 it is safe to release the environment handle:
815 DbConnectInf->FreeHenv();
818 Or, if the long form of the constructor was used and the constructor was allowed
819 to allocate its own SQL environment handle, leaving scope or destruction of the
820 wxDbConnectInf will free the handle automatically.
826 \normalbox{Remember to never release this environment handle if there are any
827 connections still using the handle.
}
829 \subsection{wxODBC - Known Issues
}\label{wxodbcknownissues
}
831 As with creating wxWidgets, writing the wxODBC classes was not the simple
832 task of writing an application to run on a single type of computer system.
833 The classes need to be cross-platform for different operating systems, and
834 they also needed to take in to account different database manufacturers and
835 different ODBC driver manufacturers. Because of all the possible combinations
836 of OS/database/drivers, it is impossible to say that these classes will work
837 perfectly with datasource ABC, ODBC driver XYZ, on platform LMN. You may run
838 into some incompatibilities or unsupported features when moving your
839 application from one environment to another. But that is what makes
840 cross-platform programming fun. It also pinpoints one of the great
841 things about open source software. It can evolve!
843 The most common difference between different database/ODBC driver
844 manufacturers in regards to these wxODBC classes is the lack of
845 standard error codes being returned to the calling program. Sometimes
846 manufacturers have even changed the error codes between versions of
847 their databases/drivers.
849 In all the tested databases, every effort has been made to determine
850 the correct error codes and handle them in the class members that need
851 to check for specific error codes (such as TABLE DOES NOT EXIST when
852 you try to open a table that has not been created yet). Adding support
853 for additional databases in the future requires adding an entry for the
854 database in the
\helpref{wxDb::Dbms
}{wxdbdbms
} function, and then handling any error codes
855 returned by the datasource that do not match the expected values.
859 Following is a list of known issues and incompatibilities that the
860 wxODBC classes have between different datasources. An up to date
861 listing of known issues can be seen in the comments of the source
862 for
\helpref{wxDb::Dbms
}{wxdbdbms
}.
865 \begin{itemize
}\itemsep=
0pt
866 \item Currently the only database supported by the wxODBC classes to support VIEWS
871 NOTE: dBase is not a true ODBC datasource. You only have access to as much
872 functionality as the driver can emulate.
874 \begin{itemize
}\itemsep=
0pt
875 \item Does not support the SQL
\_TIMESTAMP structure
876 \item Supports only one cursor and one connect (apparently? with Microsoft driver only?)
877 \item Does not automatically create the primary index if the 'keyField' param of SetColDef is true. The user must create ALL indexes from their program with calls to
\helpref{wxDbTable::CreateIndex
}{wxdbtablecreateindex
}
878 \item Table names can only be
8 characters long
879 \item Column names can only be
10 characters long
880 \item Currently cannot CREATE a dBase table - bug or limitation of the drivers used??
881 \item Currently cannot insert rows that have integer columns - bug??
885 \begin{itemize
}\itemsep=
0pt
886 \item To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added after every table name involved in the query/join if that table's matching record(s) are to be locked
887 \item Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
890 {\it SYBASE (Enterprise)
}
891 \begin{itemize
}\itemsep=
0pt
892 \item If a column is part of the Primary Key, the column cannot be NULL
893 \item Maximum row size is somewhere in the neighborhood of
1920 bytes
897 \begin{itemize
}\itemsep=
0pt
898 \item If a column is part of the Primary Key, the column cannot be NULL.
899 \item Cannot support selecting for update
[\helpref{wxDbTable::CanSelectForUpdate
}{wxdbtablecanselectforupdate
}]. Always returns false.
900 \item Columns that are part of primary or secondary keys must be defined as being NOT NULL when they are created. Some code is added in
\helpref{wxDbTable::CreateIndex
}{wxdbtablecreateindex
} to try to adjust the column definition if it is not defined correctly, but it is experimental (as of wxWidgets v2.2
.1)
901 \item Does not support sub-queries in SQL statements
905 \begin{itemize
}\itemsep=
0pt
906 \item Does not support the keywords 'ASC' or 'DESC' as of release v6.5
.0
907 \item Does not support sub-queries in SQL statements
911 \begin{itemize
}\itemsep=
0pt
912 \item Columns which are part of a primary key must be declared as NOT NULL
915 {\bf UNICODE with wxODBC classes
}
917 As of v2.6 of wxWidgets, the wxODBC classes now fully support the compilation
918 and use of the classes in a Unicode build of wxWidgets, assuming the compiler
919 and OS on which the program will be compiled/run is Unicode capable.
921 The one major difference in writing code that can be compiled in either
922 unicode or non-unicode builds that is specific to the wxODBC classes is to
923 use the SQL
\_C\_WXCHAR datatype for string columns rather than SQL
\_C\_CHAR or
926 \subsection{wxODBC - Sample Code
}\label{wxodbcsamplecode1
}
928 Simplest example of establishing/opening a connection to an ODBC datasource,
929 binding variables to the columns for read/write usage, opening an
930 existing table in the datasource, inserting a record, setting query parameters
931 (where/orderBy/from), querying the datasource, reading each row of the
932 result set, deleting a record, releasing the connection, then cleaning up.
934 NOTE: Very basic error handling is shown here, to reduce the size of the
935 code and to make it more easily readable. The HandleError() function uses the wxDbLogExtendedErrorMsg() function for retrieving database error messages.
938 // ----------------------------------------------------------------------------
940 // ----------------------------------------------------------------------------
941 #include "wx/log.h" // #included to enable output of messages only
942 #include "wx/dbtable.h"
944 // ----------------------------------------------------------------------------
945 // FUNCTION USED FOR HANDLING/DISPLAYING ERRORS
946 // ----------------------------------------------------------------------------
947 // Very generic error handling function.
948 // If a connection to the database is passed in, then we retrieve all the
949 // database errors for the connection and add them to the displayed message
950 int HandleError(wxString errmsg, wxDb *pDb=NULL)
952 // Retrieve all the error message for the errors that occurred
955 // Get the database errors and append them to the error message
956 allErrors = wxDbLogExtendedErrorMsg(errmsg.c_str(), pDb,
0,
0);
960 // Do whatever you wish with the error message here
961 // wxLogDebug() is called inside wxDbLogExtendedErrorMsg() so this
962 // console program will show the errors in the console window,
963 // but these lines will show the errors in RELEASE builds also
964 wxFprintf(stderr, wxT("
\n%s\n"), allErrors.c_str());
971 // ----------------------------------------------------------------------------
973 // ----------------------------------------------------------------------------
974 int main(int argc, char **argv)
976 wxDbConnectInf *DbConnectInf = NULL; // DB connection information
978 wxDb *db = NULL; // Database connection
980 wxDbTable *table = NULL; // Data table to access
981 const wxChar tableName
[] = wxT("USERS"); // Name of database table
982 const UWORD numTableColumns =
2; // Number table columns
983 wxChar FirstName
[50+
1]; // column data: "FIRST_NAME"
984 wxChar LastName
[50+
1]; // column data: "LAST_NAME"
986 wxString msg; // Used for display messages
988 // -----------------------------------------------------------------------
989 // DEFINE THE CONNECTION HANDLE FOR THE DATABASE
990 // -----------------------------------------------------------------------
991 DbConnectInf = new wxDbConnectInf(NULL,
992 wxT("CONTACTS-SqlServer"),
996 // Error checking....
997 if (!DbConnectInf || !DbConnectInf->GetHenv())
999 return HandleError(wxT("DB ENV ERROR: Cannot allocate ODBC env handle"));
1003 // -----------------------------------------------------------------------
1004 // GET A DATABASE CONNECTION
1005 // -----------------------------------------------------------------------
1006 db = wxDbGetConnection(DbConnectInf);
1010 return HandleError(wxT("CONNECTION ERROR - Cannot get DB connection"));
1014 // -----------------------------------------------------------------------
1015 // DEFINE THE TABLE, AND THE COLUMNS THAT WILL BE ACCESSED
1016 // -----------------------------------------------------------------------
1017 table = new wxDbTable(db, tableName, numTableColumns, wxT(""),
1018 !wxDB_QUERY_ONLY, wxT(""));
1020 // Bind the columns that you wish to retrieve. Note that there must be
1021 // 'numTableColumns' calls to SetColDefs(), to match the wxDbTable def
1023 // Not all columns need to be bound, only columns whose values are to be
1024 // returned back to the client.
1026 table->SetColDefs(
0, wxT("FIRST_NAME"), DB_DATA_TYPE_VARCHAR, FirstName,
1027 SQL_C_WXCHAR, sizeof(FirstName), true, true);
1028 table->SetColDefs(
1, wxT("LAST_NAME"), DB_DATA_TYPE_VARCHAR, LastName,
1029 SQL_C_WXCHAR, sizeof(LastName), true, true);
1032 // -----------------------------------------------------------------------
1033 // CREATE (or RECREATE) THE TABLE IN THE DATABASE
1034 // -----------------------------------------------------------------------
1035 if (!table->CreateTable(true)) //NOTE: No CommitTrans is required
1037 return HandleError(wxT("TABLE CREATION ERROR: "), table->GetDb());
1041 // -----------------------------------------------------------------------
1042 // OPEN THE TABLE FOR ACCESS
1043 // -----------------------------------------------------------------------
1046 return HandleError(wxT("TABLE OPEN ERROR: "), table->GetDb());
1050 // -----------------------------------------------------------------------
1051 // INSERT A NEW ROW INTO THE TABLE
1052 // -----------------------------------------------------------------------
1053 wxStrcpy(FirstName, wxT("JULIAN"));
1054 wxStrcpy(LastName, wxT("SMART"));
1055 if (!table->Insert())
1057 return HandleError(wxT("INSERTION ERROR: "), table->GetDb());
1060 // Must commit the insert to write the data to the DB
1061 table->GetDb()->CommitTrans();
1064 // -----------------------------------------------------------------------
1065 // RETRIEVE ROWS FROM THE TABLE BASED ON SUPPLIED CRITERIA
1066 // -----------------------------------------------------------------------
1067 // Set the WHERE clause to limit the result set to return
1068 // all rows that have a value of 'JULIAN' in the FIRST_NAME
1069 // column of the table.
1070 table->SetWhereClause(wxT("FIRST_NAME = 'JULIAN'"));
1072 // Result set will be sorted in ascending alphabetical
1073 // order on the data in the 'LAST_NAME' column of each row
1074 table->SetOrderByClause(wxT("LAST_NAME"));
1076 // No other tables (joins) are used for this query
1077 table->SetFromClause(wxT(""));
1079 // Instruct the datasource to perform a query based on the
1080 // criteria specified above in the where/orderBy/from clauses.
1081 if (!table->Query())
1083 return HandleError(wxT("QUERY ERROR: "), table->GetDb());
1086 // Loop through all rows matching the query criteria until
1087 // there are no more records to read
1088 while (table->GetNext())
1090 msg.Printf(wxT("Row #
%lu -- First Name : %s Last Name is %s"),
1091 table->GetRowNum(), FirstName, LastName);
1093 // Code to display 'msg' here
1094 wxLogMessage(wxT("
\n%s\n"), msg.c_str());
1098 // -----------------------------------------------------------------------
1099 // DELETE A ROW FROM THE TABLE
1100 // -----------------------------------------------------------------------
1101 // Select the row which has FIRST_NAME of 'JULIAN' and LAST_NAME
1102 // of 'SMART', then delete the retrieved row
1104 if (!table->DeleteWhere(wxT("FIRST_NAME = 'JULIAN' and LAST_NAME = 'SMART'")))
1106 return HandleError(wxT("DELETION ERROR: "), table->GetDb());
1109 // Must commit the deletion to the database
1110 table->GetDb()->CommitTrans();
1113 // -----------------------------------------------------------------------
1114 // TAKE CARE OF THE ODBC CLASS INSTANCES THAT WERE BEING USED
1115 // -----------------------------------------------------------------------
1116 // If the wxDbTable instance was successfully created
1117 // then delete it as we are done with it now.
1120 // Free the cached connection
1121 // (meaning release it back in to the cache of datasource
1122 // connections) for the next time a call to wxDbGetConnection()
1124 wxDbFreeConnection(db);
1128 // -----------------------------------------------------------------------
1129 // CLEANUP BEFORE EXITING APP
1130 // -----------------------------------------------------------------------
1131 // The program is now ending, so we need to close
1132 // any cached connections that are still being
1134 wxDbCloseConnections();
1136 // Release the environment handle that was created
1137 // for use with the ODBC datasource connections
1138 wxDELETE(DbConnectInf);
1140 wxUnusedVar(argc); // Here just to prevent compiler warnings
1141 wxUnusedVar(argv); // Here just to prevent compiler warnings
1147 \subsection{A selection of SQL commands
}\label{sqlcommands
}
1149 The following is a very brief description of some common SQL commands, with
1152 \wxheading{See also
}
1154 \helpref{Database classes overview
}{odbcoverview
}
1156 \subsubsection{Create
}\label{odbccreateexample
}
1164 (BookNumber INTEGER PRIMARY KEY
1165 , CategoryCode CHAR(
2) DEFAULT 'RO' NOT NULL
1166 , Title VARCHAR(
100) UNIQUE
1167 , NumberOfPages SMALLINT
1168 , RetailPriceAmount NUMERIC(
5,
2)
1172 \subsubsection{Insert
}\label{odbcinsertexample
}
1174 Inserts records into a table.
1180 (BookNumber, CategoryCode, Title)
1181 VALUES(
5, 'HR', 'The Lark Ascending')
1184 \subsubsection{Select
}\label{odbcselectexample
}
1186 The Select operation retrieves rows and columns from a table. The criteria
1187 for selection and the columns returned may be specified.
1191 {\tt SELECT * FROM Book
}
1193 Selects all rows and columns from table Book.
1195 {\tt SELECT Title, RetailPriceAmount FROM Book WHERE RetailPriceAmount >
20.0}
1197 Selects columns Title and RetailPriceAmount from table Book, returning only
1198 the rows that match the WHERE clause.
1200 {\tt SELECT * FROM Book WHERE CatCode = 'LL' OR CatCode = 'RR'
}
1202 Selects all columns from table Book, returning only
1203 the rows that match the WHERE clause.
1205 {\tt SELECT * FROM Book WHERE CatCode IS NULL
}
1207 Selects all columns from table Book, returning only rows where the CatCode column
1210 {\tt SELECT * FROM Book ORDER BY Title
}
1212 Selects all columns from table Book, ordering by Title, in ascending order. To specify
1213 descending order, add DESC after the ORDER BY Title clause.
1215 {\tt SELECT Title FROM Book WHERE RetailPriceAmount >=
20.0 AND RetailPriceAmount <=
35.0}
1217 Selects records where RetailPriceAmount conforms to the WHERE expression.
1219 \subsubsection{Update
}\label{odbcupdateexample
}
1221 Updates records in a table.
1225 {\tt UPDATE Incident SET X =
123 WHERE ASSET = 'BD34'
}
1227 This example sets a field in column `X' to the number
123, for the record
1228 where the column ASSET has the value `BD34'.