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