]>
Commit | Line | Data |
---|---|---|
a660d684 KB |
1 | \section{Database classes overview}\label{odbcoverview} |
2 | ||
fc2171bd | 3 | Following is a detailed overview of how to use the wxWidgets ODBC classes - \helpref{wxDb}{wxdb} |
2564094b | 4 | and \helpref{wxDbTable}{wxdbtable} and their associated functions. These are |
b25ba5b7 | 5 | the ODBC classes donated by Remstar International, and are collectively |
f7292ebe | 6 | referred to herein as the wxODBC classes. |
b25ba5b7 GT |
7 | |
8 | \subsection{wxDb/wxDbTable wxODBC Overview}\label{wxodbcoverview} | |
9 | ||
10 | Classes: \helpref{wxDb}{wxdb}, \helpref{wxDbTable}{wxdbtable} | |
11 | ||
2564094b | 12 | The wxODBC classes were designed for database independence. Although SQL and |
b25ba5b7 GT |
13 | ODBC both have standards which define the minimum requirements they must |
14 | support to be in compliance with specifications, different database vendors | |
2564094b | 15 | may implement things slightly differently. One example of this is that Oracle |
b25ba5b7 | 16 | requires all user names for the datasources to be supplied in uppercase |
2564094b | 17 | characters. In situations like this, the wxODBC classes have been written |
b25ba5b7 | 18 | to make this transparent to the programmer when using functions that require |
2564094b | 19 | database-specific syntax. |
b25ba5b7 GT |
20 | |
21 | Currently several major databases, along with other widely used databases, | |
2564094b | 22 | have been tested and supported through the wxODBC classes. The list of |
b25ba5b7 GT |
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: | |
26 | ||
27 | \begin{itemize}\itemsep=0pt | |
998abc15 | 28 | \item DB2 |
b25ba5b7 | 29 | \item DBase (IV, V)** |
998abc15 | 30 | \item Firebird |
b25ba5b7 | 31 | \item INFORMIX |
509cd921 | 32 | \item Interbase |
998abc15 GT |
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) | |
509cd921 | 37 | \item Pervasive SQL |
998abc15 GT |
38 | \item PostgreSQL |
39 | \item Sybase (ASA and ASE) | |
40 | \item XBase Sequiter | |
41 | \item VIRTUOSO | |
b25ba5b7 GT |
42 | \end{itemize} |
43 | ||
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. | |
47 | ||
48 | **dBase is not truly an ODBC datasource, but there are drivers which can | |
2564094b | 49 | emulate much of the functionality of an ODBC connection to a dBase table. |
b25ba5b7 GT |
50 | See the \helpref{wxODBC Known Issues}{wxodbcknownissues} section of this |
51 | overview for details. | |
52 | ||
53 | ||
54 | \subsection{wxODBC Where To Start}\label{wxodbcwheretostart} | |
55 | ||
56 | First, if you are not familiar with SQL and ODBC, go to your local bookstore | |
2564094b | 57 | and pick up a good book on each. This documentation is not meant to teach |
b25ba5b7 GT |
58 | you many details about SQL or ODBC, though you may learn some just from |
59 | immersion in the subject. | |
60 | ||
61 | If you have worked with non-SQL/ODBC datasources before, there are some | |
2564094b | 62 | things you will need to un-learn. First some terminology as these phrases will |
b25ba5b7 GT |
63 | be used heavily in this section of the manual. |
64 | ||
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 | |
69 | columns of data.} | |
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 | |
2564094b | 74 | the ODBC driver which in turn has a connection to the target datasource. |
b25ba5b7 | 75 | Datasource connections can have a virtually unlimited number of wxDbTable |
2564094b | 76 | instances using the same connect (dependent on the ODBC driver). A separate |
b25ba5b7 GT |
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 | |
2564094b | 79 | table. See the class documentation on |
b25ba5b7 | 80 | \helpref{wxDb::CommitTrans}{wxdbcommittrans} and |
2564094b | 81 | \helpref{wxDb::RollbackTrans}{wxdbrollbacktrans}.)} |
b25ba5b7 GT |
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 | |
86 | table.} | |
87 | \twocolitem{Query}{Request from the client to the datasource asking for | |
2564094b | 88 | the data that matches the requirements specified in the users request. When |
b25ba5b7 GT |
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 | |
2564094b | 92 | in a query sent to the datasource. Dependent on drivers, a result set |
b25ba5b7 GT |
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.} | |
2564094b | 95 | \twocolitem{Cursor}{A logical pointer into the result set that a query |
b25ba5b7 GT |
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 | |
2564094b JS |
99 | through the result set. Cursors can always scroll forward sequentially in |
100 | the result set (FORWARD ONLY scrolling cursors). With Forward only scrolling | |
b25ba5b7 GT |
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 | |
2564094b | 104 | the result set. If BACKWARD scrolling cursors are supported by both the |
b25ba5b7 GT |
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 | |
2564094b | 109 | \helpref{wxDbTable::GetLast}{wxdbtablegetlast}). If the datasource or the |
b25ba5b7 GT |
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 | |
2564094b JS |
115 | previously committed. Note that Commit and Rollbacks are done on a |
116 | connection, not on individual tables. All tables which use a shared | |
b25ba5b7 GT |
117 | connection to the datasource are all committed/rolled back at the same |
118 | time when a call to | |
119 | \helpref{wxDb::CommitTrans}{wxdbcommittrans} or | |
120 | \helpref{wxDb::RollbackTrans}{wxdbrollbacktrans} is made.} | |
2564094b | 121 | \twocolitem{Index}{Indexes are datasource-maintained lookup structures |
b25ba5b7 | 122 | that allow the datasource to quickly locate data rows based on the values |
2564094b JS |
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 | |
b25ba5b7 GT |
125 | unique key index construction can make datasource queries nearly instantaneous.} |
126 | \end{twocollist} | |
127 | ||
128 | Before you are able to read data from a data table in a datasource, you must | |
2564094b | 129 | have a connection to the datasource. Each datasource connection may be used |
b25ba5b7 GT |
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 | |
2564094b | 132 | the client workstation). Multiple connections can be opened to the same |
b25ba5b7 GT |
133 | datasource by the same client (number of concurrent connections is dependent |
134 | on the driver and datasource configuration). | |
135 | ||
136 | When a query is performed, the client passes the query to the ODBC driver, | |
2564094b | 137 | and the driver then translates it and passes it along to the datasource. The |
b25ba5b7 GT |
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 | |
2564094b JS |
140 | for the requested data. The client simply waits for a status to come back |
141 | through the ODBC driver from the datasource. | |
b25ba5b7 GT |
142 | |
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 | |
2564094b | 145 | queued on. The client does not receive this data. The client must request |
b25ba5b7 GT |
146 | some or all of the result set to be returned before any data rows are |
147 | returned to the client application. | |
148 | ||
149 | Result sets do not need to include all columns of every row matching the | |
2564094b | 150 | query. In fact, result sets can actually be joinings of columns from two |
b25ba5b7 GT |
151 | or more data tables, may have derived column values, or calculated values |
152 | returned. | |
153 | ||
154 | For each result set, a cursor is maintained (typically by the database) | |
2564094b | 155 | which keeps track of where in the result set the user currently is. |
b25ba5b7 | 156 | Depending on the database, ODBC driver, and how you configured the |
fc2171bd | 157 | wxWidgets ODBC settings in setup.h (see \helpref{wxODBC - Compiling}{wxodbccompiling}), cursors can be |
2564094b JS |
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, | |
b25ba5b7 | 160 | as the data is read by the client application, it will read row 1, then 2, |
2564094b | 161 | then 3, etc. With forward only cursors, once the cursor has moved to |
b25ba5b7 | 162 | the next row, the previous row cannot be accessed again without re-querying |
2564094b | 163 | the datasource for the result set over again. Backward scrolling cursors |
b25ba5b7 GT |
164 | allow you to request the previous row from the result set, actually |
165 | scrolling the cursor backward. | |
166 | ||
167 | Backward scrolling cursors are not supported on all database/driver | |
2564094b JS |
168 | combinations. For this reason, forward-only cursors are the default in |
169 | the wxODBC classes. If your datasource does support backward scrolling | |
b25ba5b7 | 170 | cursors and you wish to use them, make the appropriate changes in setup.h |
2564094b | 171 | to enable them (see \helpref{wxODBC - Compiling}{wxodbccompiling}). For greatest portability between |
b25ba5b7 | 172 | datasources, writing your program in such a way that it only requires |
2564094b | 173 | forward scrolling cursors is your best bet. On the other hand, if you are |
b25ba5b7 GT |
174 | focusing on using only datasources that support backward scrolling cursors, |
175 | potentially large performance benefits can be gained from using them. | |
176 | ||
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 | |
2564094b JS |
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. | |
b25ba5b7 GT |
182 | Cursors are a limited resource, so use care in creating large numbers of |
183 | cursors. | |
184 | ||
185 | Additional cursors can be created if necessary with the | |
2564094b JS |
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 | |
b25ba5b7 GT |
189 | from the datasource while still maintaining the original cursor position in |
190 | the first result set. | |
191 | ||
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 | |
2564094b | 196 | perform are to be recorded as permanent. Until a commit is performed, |
b25ba5b7 GT |
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 | |
2564094b | 199 | auto-commit). NOTE: With most datasources, until the commit is |
b25ba5b7 | 200 | performed, any cursor that is open on that same datasource connection |
2564094b JS |
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 | |
b25ba5b7 GT |
203 | though. |
204 | ||
2564094b | 205 | A rollback is basically an UNDO command on the datasource connection. When |
b25ba5b7 GT |
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. | |
208 | ||
209 | NOTE: Commits/Rollbacks are done on datasource connections (wxDb instances) | |
2564094b | 210 | not on the wxDbTable instances. This means that if more than one table |
b25ba5b7 GT |
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. | |
214 | ||
b25ba5b7 GT |
215 | \subsection{wxODBC - Configuring your system for ODBC use}\label{wxodbcconfiguringyoursystem} |
216 | ||
217 | Before you are able to access a datasource, you must have installed and | |
2564094b JS |
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. | |
b25ba5b7 GT |
220 | |
221 | Most database vendors provide at least a minimal ODBC driver with their | |
2564094b JS |
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. | |
226 | ||
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 | |
b25ba5b7 GT |
231 | platforms and databases. |
232 | ||
2564094b | 233 | Under Microsoft Windows, install the ODBC driver you are planning to use. You |
b25ba5b7 | 234 | will then use the ODBC Administrator in the Control Panel to configure an |
2564094b | 235 | instance of the driver for your intended datasource. Note that with all |
b25ba5b7 | 236 | flavors of NT, this configuration can be set up as a System or User DSN |
2564094b | 237 | (datasource name). Configuring it as a system resource will make it |
b25ba5b7 | 238 | available to all users (if you are logged in as 'administrator'), otherwise |
2564094b | 239 | the datasource will only be available to the user who configured the DSN. |
b25ba5b7 | 240 | |
2564094b JS |
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. | |
fc2171bd | 243 | (Note: wxWidgets currently includes a version of iODBC.) Then you must create the file "~/.odbc.ini" (or optionally create |
2564094b JS |
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 | |
b25ba5b7 GT |
246 | odbc.ini file for use with the "samples/db" sample program using MySQL: |
247 | ||
248 | \begin{verbatim} | |
249 | [contacts] | |
250 | Trace = Off | |
251 | TraceFile= stderr | |
252 | Driver = /usr/local/lib/libmyodbc.so | |
253 | DSN = contacts | |
254 | SERVER = 192.168.1.13 | |
255 | USER = qet | |
256 | PASSWORD = | |
257 | PORT = 3306 | |
258 | \end{verbatim} | |
259 | ||
b25ba5b7 GT |
260 | \subsection{wxODBC - Compiling}\label{wxodbccompiling} |
261 | ||
fc2171bd | 262 | The wxWidgets setup.h file has several settings in it pertaining to compiling |
b25ba5b7 GT |
263 | the wxODBC classes. |
264 | ||
265 | \begin{twocollist}\itemsep=0pt | |
509cd921 | 266 | \twocolitem{wxUSE\_ODBC}{This must be set to 1 in order for the compiler to |
2564094b JS |
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.} | |
509cd921 | 269 | \twocolitem{wxODBC\_FWD\_ONLY\_CURSORS}{When a new database connection is |
b25ba5b7 GT |
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 | |
2564094b | 273 | cursors). This default can be overridden by passing a second parameter to |
b25ba5b7 | 274 | either the \helpref{wxDbGetConnection}{wxdbfunctions} or |
b236c10f | 275 | \helpref{wxDb constructor}{wxdbctor}. The default is 1.} |
509cd921 | 276 | \twocolitem{wxODBC\_BACKWARD\_COMPATABILITY}{Between v2.0 and 2.2, massive |
b25ba5b7 | 277 | renaming efforts were done to the ODBC classes to get naming conventions |
fc2171bd | 278 | similar to those used throughout wxWidgets, as well as to preface all wxODBC |
2564094b | 279 | classes names and functions with a wxDb preface. Because this renaming would |
b25ba5b7 GT |
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 | |
7af3ca16 | 282 | old naming conventions. These deprecated names are all {\tt\#}define'd to their |
b25ba5b7 | 283 | corresponding new function names at the end of the db.cpp/dbtable.cpp source |
2564094b JS |
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 | |
b25ba5b7 GT |
286 | is 0.} |
287 | \end{twocollist} | |
288 | ||
289 | {\it Under MS Windows} | |
290 | ||
291 | You are required to include the "odbc32.lib" provided by your compiler vendor | |
2564094b | 292 | in the list of external libraries to be linked in. If using the makefiles |
fc2171bd | 293 | supplied with wxWidgets, this library should already be included for use with |
b25ba5b7 GT |
294 | makefile.b32, makefile.vc, and makefile.g95. |
295 | ||
b25ba5b7 GT |
296 | \normalbox{MORE TO COME} |
297 | ||
298 | {\it Under Unix} | |
6b2878de | 299 | --with-odbc flag for configure |
b25ba5b7 GT |
300 | |
301 | \normalbox{MORE TO COME} | |
302 | ||
b25ba5b7 GT |
303 | \subsection{wxODBC - Basic Step-By-Step Guide}\label{wxodbcstepbystep} |
304 | ||
305 | To use the classes in an application, there are eight basic steps: | |
306 | ||
307 | \begin{itemize}\itemsep=0pt | |
308 | \item Define datasource connection information | |
309 | \item Get a datasource connection | |
310 | \item Create table definition | |
311 | \item Open the table | |
312 | \item Use the table | |
313 | \item Close the table | |
314 | \item Close the datasource connection | |
315 | \item Release the ODBC environment handle | |
316 | \end{itemize} | |
317 | ||
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 | |
2564094b JS |
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 | |
b25ba5b7 GT |
322 | complete code snippet is provided at the end of this overview that shows a |
323 | complete working flow of all these steps (see | |
80793cda | 324 | \helpref{wxODBC - Sample Code}{wxodbcsamplecode1}). |
b25ba5b7 | 325 | |
b25ba5b7 GT |
326 | {\bf Define datasource connection information} |
327 | ||
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 | |
2564094b | 330 | Authorization string (password). A fourth piece of information, a default |
b25ba5b7 GT |
331 | directory indicating where the data file is stored, is required for Text and |
332 | dBase drivers for ODBC. | |
333 | ||
fc2171bd | 334 | The wxWidgets data class wxDbConnectInf exists for holding all of these |
b25ba5b7 GT |
335 | values, plus some others that may be desired. |
336 | ||
b25ba5b7 | 337 | The 'Henv' member is the environment handle used to access memory for use by the |
2564094b | 338 | ODBC driver. Use of this member is described below in the "Getting a Connection |
b25ba5b7 GT |
339 | to the Datasource" section. |
340 | ||
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). | |
343 | ||
2564094b | 344 | The 'Uid' is the User ID that is to be used to log in to the datasource. This |
b25ba5b7 | 345 | User ID must already have been created and assigned rights within the |
2564094b | 346 | datasource to which you are connecting. The user that the connection is |
b25ba5b7 GT |
347 | establish by will determine what rights and privileges the datasource |
348 | connection will allow the program to have when using the connection that | |
2564094b | 349 | this connection information was used to establish. Some datasources are |
b25ba5b7 GT |
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. | |
354 | ||
2564094b JS |
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. | |
b25ba5b7 GT |
358 | It is passed verbatim to the datasource, so you must use the case that the |
359 | datasource is expecting. | |
360 | ||
361 | The 'defaultDir' member is used with file based datasources (i.e. dBase, | |
2564094b JS |
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 | |
b25ba5b7 GT |
364 | slashes '/' rather than backslashes '\' to avoid compatibility differences |
365 | between ODBC drivers. | |
366 | ||
2564094b | 367 | The other fields are currently unused. The intent of these fields are that |
b25ba5b7 | 368 | they will be used to write our own ODBC Administrator type program that will |
2564094b | 369 | work on both MSW and Un*x systems, regardless of the datasource. Very little |
b25ba5b7 GT |
370 | work has been done on this to date. |
371 | ||
b25ba5b7 GT |
372 | {\bf Get a Datasource Connection} |
373 | ||
2564094b | 374 | There are two methods of establishing a connection to a datasource. You |
b25ba5b7 GT |
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. | |
378 | ||
379 | Regardless of which method you use, you must first have a fully populated | |
2564094b JS |
380 | wxDbConnectInf object. In the wxDbConnectInf instance, provide a valid |
381 | Dns, Uid, and AuthStr (along with a 'defaultDir' if necessary). Before | |
b25ba5b7 GT |
382 | using this though, you must allocate an environment handle to the 'Henv' |
383 | member. | |
384 | ||
385 | \begin{verbatim} | |
386 | wxDbConnectInf DbConnectInf; | |
2b5f62a0 VZ |
387 | DbConnectInf.SetDsn("MyDSN"); |
388 | DbConnectInf.SetUserID("MyUserName"); | |
9fe17bd3 GT |
389 | DbConnectInf.SetPassword("MyPassword"); |
390 | DbConnectInf.SetDefaultDir(""); | |
b25ba5b7 GT |
391 | \end{verbatim} |
392 | ||
393 | To allocate an environment handle for the ODBC connection to use, the | |
19320af4 GT |
394 | wxDbConnectInf class has a datasource independent method for creating |
395 | the necessary handle: | |
b25ba5b7 GT |
396 | |
397 | \begin{verbatim} | |
9fe17bd3 | 398 | if (DbConnectInf.AllocHenv()) |
b25ba5b7 GT |
399 | { |
400 | wxMessageBox("Unable to allocate an ODBC environment handle", | |
401 | "DB CONNECTION ERROR", wxOK | wxICON_EXCLAMATION); | |
402 | return; | |
403 | } | |
404 | \end{verbatim} | |
405 | ||
19320af4 | 406 | When the wxDbConnectInf::AllocHenv() function is called successfully, a |
cc81d32f | 407 | value of true will be returned. A value of false means allocation failed, |
19320af4 | 408 | and the handle will be undefined. |
9fe17bd3 GT |
409 | |
410 | A shorter form of doing the above steps is encapsulated into the | |
411 | long form of the constructor for wxDbConnectInf. | |
412 | ||
9fe17bd3 GT |
413 | \begin{verbatim} |
414 | wxDbConnectInf *DbConnectInf; | |
415 | ||
416 | DbConnectInf = new wxDbConnectInf(NULL, "MyDSN", "MyUserName", | |
417 | "MyPassword", ""); | |
418 | \end{verbatim} | |
419 | ||
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 | |
2564094b | 422 | construction. This handle is also managed for the life of wxDbConnectInf |
9fe17bd3 | 423 | instance, and is freed automatically upon destruction of the instance. |
b25ba5b7 | 424 | |
9fe17bd3 GT |
425 | Once the wxDbConnectInf instance is initialized, you are ready to |
426 | connect to the datasource. | |
b25ba5b7 GT |
427 | |
428 | To manually create datasource connections, you must create a wxDb | |
429 | instance, and then open it. | |
430 | ||
431 | \begin{verbatim} | |
9fe17bd3 GT |
432 | wxDb *db = new wxDb(DbConnectInf->GetHenv()); |
433 | ||
434 | opened = db->Open(DbConnectInf); | |
b25ba5b7 GT |
435 | \end{verbatim} |
436 | ||
9fe17bd3 | 437 | The first line does the house keeping needed to initialize all |
2564094b | 438 | the members of the wxDb class. The second line actually sends the request |
b25ba5b7 GT |
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}. | |
441 | ||
2564094b JS |
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 | |
b25ba5b7 GT |
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 | |
2564094b | 447 | needing to do the coding. |
b25ba5b7 GT |
448 | |
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 | |
451 | type wxDbConnectInf: | |
452 | ||
453 | \begin{verbatim} | |
9fe17bd3 | 454 | db = wxDbGetConnection(DbConnectInf); |
b25ba5b7 GT |
455 | \end{verbatim} |
456 | ||
2564094b | 457 | The wxDb pointer that is returned is both initialized and opened. If |
b25ba5b7 GT |
458 | something failed in creating or opening the connection, the return value |
459 | from \helpref{wxDbGetConnection}{wxdbfunctions} will be NULL. | |
460 | ||
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 | |
2564094b JS |
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 | |
b25ba5b7 GT |
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 | |
2564094b | 469 | using the same connection information (Dsn, Uid, AuthStr). The cached |
b25ba5b7 GT |
470 | connections remain cached until a call to \helpref{wxDbCloseConnections}{wxdbfunctions} is made, |
471 | at which time all cached connections are closed and deleted. | |
472 | ||
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 | |
2564094b | 475 | performance boost as well. Each time that a new connection is created |
b25ba5b7 GT |
476 | (not retrieved from the cache of free connections), the wxODBC classes |
477 | perform many queries against the datasource to determine the datasource's | |
2564094b | 478 | datatypes and other fundamental behaviours. Depending on the hardware, |
b25ba5b7 | 479 | network bandwidth, and datasource speed, this can in some cases take a |
2564094b JS |
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 | |
b25ba5b7 | 482 | datasource connections rather than creating/deleting, creating/deleting |
2564094b | 483 | connections can be quite a time-saver. |
b25ba5b7 | 484 | |
2564094b JS |
485 | Another time-saver is the "copy connection" features of both |
486 | \helpref{wxDb::Open}{wxdbopen} and \helpref{wxDbGetConnection}{wxdbfunctions}. | |
b25ba5b7 GT |
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 | |
2564094b | 489 | benefit of copying existing connection settings. The |
b25ba5b7 GT |
490 | \helpref{wxDbGetConnection}{wxdbfunctions} function automatically does this |
491 | for you, checking the Dsn, Uid, and AuthStr parameters when you request | |
2564094b | 492 | a connection for any existing connections that use those same settings. |
b25ba5b7 GT |
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. | |
496 | ||
2564094b | 497 | One final note on creating a connection. When a connection is created, it |
b25ba5b7 | 498 | will default to only allowing cursor scrolling to be either forward only, |
2564094b | 499 | or both backward and forward scrolling. The default behavior is |
509cd921 | 500 | determined by the setting {\tt wxODBC\_FWD\_ONLY\_CURSORS} in setup.h when you |
fc2171bd | 501 | compile the wxWidgets library. The library default is to only support |
b25ba5b7 GT |
502 | forward scrolling cursors only, though this can be overridden by parameters |
503 | for wxDb() constructor or the \helpref{wxDbGetConnection}{wxdbfunctions} | |
2564094b JS |
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 | |
b25ba5b7 | 507 | backward scrolling cursors, you must be certain that both your datasource |
2564094b | 508 | and ODBC driver fully support backward scrolling cursors. See the small |
b25ba5b7 GT |
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 | |
511 | class documentation. | |
512 | ||
b25ba5b7 GT |
513 | {\bf Create Table Definition} |
514 | ||
515 | Data can be accessed in a datasource's tables directly through various | |
2564094b | 516 | functions of the wxDb class (see \helpref{wxDb::GetData}{wxdbgetdata}). But to make life much |
b25ba5b7 GT |
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. | |
519 | ||
520 | The first step in accessing data in a datasource's tables via the wxDbTable | |
521 | class is to create a wxDbTable instance. | |
522 | ||
523 | \begin{verbatim} | |
9fe17bd3 GT |
524 | table = new wxDbTable(db, tableName, numTableColumns, "", |
525 | !wxDB_QUERY_ONLY, ""); | |
b25ba5b7 GT |
526 | \end{verbatim} |
527 | ||
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. | |
536 | ||
537 | Each of the above parameters are described in detail in the wxDbTable | |
538 | class' description, but one special note here about the fifth | |
2564094b JS |
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} | |
b25ba5b7 | 542 | or \helpref{wxDb::RollbackTrans}{wxdbrollbacktrans} against the datasource |
2564094b | 543 | connection used by this wxDbTable instance are ignored by this instance. If |
509cd921 | 544 | the wxDbTable instance is created with {\tt !wxDB\_QUERY\_ONLY} as shown above, |
b25ba5b7 GT |
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 | |
548 | wxDbTable instance. | |
549 | ||
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 | |
2564094b JS |
554 | wxDbTable instance. Also, with some datasources, the number of |
555 | simultaneous cursors is limited. | |
b25ba5b7 GT |
556 | |
557 | When defining the columns to be retrievable by the wxDbTable instance, you | |
2564094b | 558 | can specify anywhere from one column up to all columns in the table. |
b25ba5b7 GT |
559 | |
560 | \begin{verbatim} | |
561 | table->SetColDefs(0, "FIRST_NAME", DB_DATA_TYPE_VARCHAR, FirstName, | |
998abc15 | 562 | SQL_C_WXCHAR, sizeof(FirstName), true, true); |
b25ba5b7 | 563 | table->SetColDefs(1, "LAST_NAME", DB_DATA_TYPE_VARCHAR, LastName, |
998abc15 | 564 | SQL_C_WXCHAR, sizeof(LastName), true, true); |
b25ba5b7 GT |
565 | \end{verbatim} |
566 | ||
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). | |
570 | ||
571 | The above lines of code "bind" the datasource columns specified to the | |
2564094b | 572 | memory variables in the client application. So when the application |
b25ba5b7 GT |
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 | |
2564094b | 575 | have the column value stored into them. See the |
b25ba5b7 GT |
576 | \helpref{wxDbTable::SetColDefs}{wxdbtablesetcoldefs} |
577 | class documentation for more details on all the parameters for this function. | |
578 | ||
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}, | |
2564094b | 582 | \helpref{wxDbTable::GetPrev}{wxdbtablegetprev}, etc). The variables are not |
b25ba5b7 | 583 | initialized to any data by the wxODBC classes, and they still contain |
2564094b | 584 | undefined data after a call to \helpref{wxDbTable::Query}{wxdbtablequery}. Only |
b25ba5b7 GT |
585 | after a successful call to one of the ::GetXxxx() functions is made do the |
586 | variables contain valid data. | |
587 | ||
588 | It is not necessary to define column definitions for columns whose data is | |
2564094b | 589 | not going to be returned to the client. For example, if you want to query |
b25ba5b7 | 590 | the datasource for all users with a first name of 'GEORGE', but you only want |
509cd921 | 591 | the list of last names associated with those rows (why return the FIRST\_NAME |
b25ba5b7 GT |
592 | column every time when you already know it is 'GEORGE'), you would only have |
593 | needed to define one column above. | |
594 | ||
595 | You may have as many wxDbTable instances accessing the same table using the | |
2564094b JS |
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. | |
b25ba5b7 GT |
598 | |
599 | {\bf Open the table} | |
600 | ||
2564094b JS |
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 | |
b25ba5b7 | 604 | connected user has at least SELECT privileges for accessing the table, |
2564094b | 605 | setting up the requisite cursors, binding columns and cursors, and |
b25ba5b7 | 606 | constructing the default INSERT statement that is used when a new row is |
509cd921 | 607 | inserted into the table (non-wxDB\_QUERY\_ONLY tables only). |
b25ba5b7 GT |
608 | |
609 | \begin{verbatim} | |
610 | if (!table->Open()) | |
611 | { | |
612 | // An error occurred opening (setting up) the table | |
613 | } | |
614 | \end{verbatim} | |
615 | ||
2564094b JS |
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 | |
b25ba5b7 | 618 | could occur, such as being unable to bind columns, but these other reason |
2564094b | 619 | point to some lack of resource (like memory). Any errors generated |
b25ba5b7 GT |
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. | |
622 | ||
b25ba5b7 GT |
623 | {\bf Use the table} |
624 | ||
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 | |
3980000c | 627 | it where to get the data from, and in which sequence we want the data returned. |
b25ba5b7 GT |
628 | |
629 | \begin{verbatim} | |
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'"); | |
633 | ||
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"); | |
639 | ||
640 | // No other tables (joins) are used for this query | |
641 | table->SetFromClause(""); | |
642 | \end{verbatim} | |
643 | ||
644 | The above lines will be used to tell the datasource to return in the result | |
509cd921 | 645 | all the rows in the table whose column "FIRST\_NAME" contains the name |
b25ba5b7 GT |
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 | |
509cd921 | 649 | "DESC" keyword for datasources that support it - "LAST\_NAME DESC"). |
b25ba5b7 GT |
650 | |
651 | Specifying a blank WHERE clause will result in the result set containing | |
652 | all rows in the datasource. | |
653 | ||
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 | |
2564094b | 656 | selection criteria. What this sequence is can be hard to determine. |
b25ba5b7 | 657 | Typically it depends on the index that the datasource used to find the |
2564094b | 658 | rows which match the WHERE criteria. BEWARE - relying on the datasource |
b25ba5b7 | 659 | to return data in a certain sequence when you have not provided an ORDERBY |
2564094b | 660 | clause will eventually cause a problem for your program. Databases can be |
b25ba5b7 | 661 | tuned to be COST-based, SPEED-based, or some other basis for how it gets |
2564094b | 662 | your result set. In short, if you need your result set returned in a |
b25ba5b7 GT |
663 | specific sequence, ask for it that way by providing an ORDERBY clause. |
664 | ||
665 | Using an ORDERBY clause can be a performance hit, as the database must | |
2564094b | 666 | sort the items before making the result set available to the client. |
b25ba5b7 | 667 | Creating efficient indexes that cause the data to be "found" in the correct |
2564094b | 668 | ORDERBY sequence can be a big performance benefit. Also, in the large |
b25ba5b7 GT |
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 | |
2564094b | 671 | them. Let the database do the work for you! |
b25ba5b7 GT |
672 | |
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. | |
675 | ||
676 | The FROM clause in this example is blanked, as we are not going to be | |
2564094b | 677 | performing any table joins with this simple query. When the FROM clause |
b25ba5b7 GT |
678 | is blank, it is assumed that all columns referenced are coming from |
679 | the default table for the wxDbTable instance. | |
680 | ||
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 | |
683 | can be retrieved: | |
684 | ||
685 | \begin{verbatim} | |
686 | // Instruct the datasource to perform a query based on the | |
687 | // criteria specified above in the where/orderBy/from clauses. | |
688 | if (!table->Query()) | |
689 | { | |
690 | // An error occurred performing the query | |
691 | } | |
692 | \end{verbatim} | |
693 | ||
694 | Typically, when an error occurs when calling \helpref{wxDbTable::Query}{wxdbtablequery}, it is a | |
2564094b JS |
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} | |
b25ba5b7 GT |
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. | |
700 | ||
cc81d32f | 701 | When the \helpref{wxDbTable::Query}{wxdbtablequery} returns true, the |
b25ba5b7 | 702 | database was able to successfully complete the requested query using the |
2564094b | 703 | provided criteria. This does not mean that there are any rows in the |
b25ba5b7 GT |
704 | result set, it just mean that the query was successful. |
705 | ||
706 | \normalbox{IMPORTANT: The result created by the call to | |
2564094b | 707 | \helpref{wxDbTable::Query}{wxdbtablequery} can take one of two forms. It is |
b25ba5b7 GT |
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 | |
2564094b JS |
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 | |
b25ba5b7 | 712 | since the result set was constructed, so beware if your datasource |
2564094b | 713 | uses snapshots and call \helpref{wxDbTable::Refresh}{wxdbtablerefresh}. Most larger brand databases |
b25ba5b7 | 714 | do not use snapshots, but it is important to mention so that your application |
2564094b | 715 | can handle it properly if your datasource does.} |
b25ba5b7 GT |
716 | |
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 | |
2564094b | 719 | set into the bound memory variables. After \helpref{wxDbTable::Query}{wxdbtablequery} |
b25ba5b7 | 720 | has completed successfully, the default/current cursor is placed so it |
2564094b | 721 | is pointing just before the first record in the result set. If the |
b25ba5b7 | 722 | result set is empty (no rows matched the criteria), then any calls to |
cc81d32f | 723 | retrieve data from the result set will return false. |
b25ba5b7 GT |
724 | |
725 | \begin{verbatim} | |
726 | wxString msg; | |
727 | ||
728 | while (table->GetNext()) | |
729 | { | |
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); | |
733 | } | |
734 | \end{verbatim} | |
735 | ||
736 | The sample code above will read the next record in the result set repeatedly | |
2564094b | 737 | until the end of the result set has been reached. The first time that |
b25ba5b7 GT |
738 | \helpref{wxDbTable::GetNext}{wxdbtablegetnext} is called right after the successful |
739 | call to \helpref{wxDbTable::Query}{wxdbtablequery}, it actually returns the first record | |
740 | in the result set. | |
741 | ||
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 | |
cc81d32f | 745 | wxDbTable::GetXxxxx() functions) will return false. |
b25ba5b7 | 746 | |
b25ba5b7 GT |
747 | {\bf Close the table} |
748 | ||
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 | |
2564094b | 751 | variable go out of scope). Typically the default destructor will take |
b25ba5b7 GT |
752 | care of all that is required for cleaning up the wxDbTable instance. |
753 | ||
754 | \begin{verbatim} | |
755 | if (table) | |
756 | { | |
757 | delete table; | |
758 | table = NULL; | |
759 | } | |
760 | \end{verbatim} | |
761 | ||
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). | |
766 | ||
b25ba5b7 GT |
767 | {\bf Close the datasource connection} |
768 | ||
769 | After all tables that have been using a datasource connection have been | |
2564094b | 770 | closed (this can be verified by calling \helpref{wxDb::GetTableCount}{wxdbgettablecount} |
b25ba5b7 | 771 | and checking that it returns 0), then you may close the datasource |
2564094b | 772 | connection. The method of doing this is dependent on whether the |
b25ba5b7 GT |
773 | non-caching or caching method was used to obtain the datasource connection. |
774 | ||
775 | If the datasource connection was created manually (non-cached), closing the | |
776 | connection is done like this: | |
777 | ||
778 | \begin{verbatim} | |
779 | if (db) | |
780 | { | |
781 | db->Close(); | |
782 | delete db; | |
783 | db = NULL; | |
784 | } | |
785 | \end{verbatim} | |
786 | ||
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 | |
789 | connection(s): | |
790 | ||
791 | \begin{verbatim} | |
792 | if (db) | |
793 | { | |
794 | wxDbFreeConnection(db); | |
795 | db = NULL; | |
796 | } | |
797 | \end{verbatim} | |
798 | ||
799 | Note that the above code just frees the connection so that it can be | |
2564094b | 800 | re-used on the next call the \helpref{wxDbGetConnection}{wxdbfunctions}. To actually dispose |
b25ba5b7 GT |
801 | of the connection, releasing all of its resources (other than the |
802 | environment handle), do the following: | |
803 | ||
804 | \begin{verbatim} | |
805 | wxDbCloseConnections(); | |
806 | \end{verbatim} | |
807 | ||
b25ba5b7 GT |
808 | {\bf Release the ODBC environment handle} |
809 | ||
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: | |
813 | ||
814 | \begin{verbatim} | |
2b5f62a0 | 815 | DbConnectInf->FreeHenv(); |
9fe17bd3 | 816 | \end{verbatim} |
b25ba5b7 | 817 | |
9fe17bd3 GT |
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. | |
821 | ||
822 | \begin{verbatim} | |
823 | delete DbConnectInf; | |
b25ba5b7 GT |
824 | \end{verbatim} |
825 | ||
826 | \normalbox{Remember to never release this environment handle if there are any | |
5f6d6405 | 827 | connections still using the handle.} |
b25ba5b7 | 828 | |
b25ba5b7 GT |
829 | \subsection{wxODBC - Known Issues}\label{wxodbcknownissues} |
830 | ||
fc2171bd | 831 | As with creating wxWidgets, writing the wxODBC classes was not the simple |
2564094b | 832 | task of writing an application to run on a single type of computer system. |
b25ba5b7 GT |
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 | |
2564094b | 835 | different ODBC driver manufacturers. Because of all the possible combinations |
b25ba5b7 | 836 | of OS/database/drivers, it is impossible to say that these classes will work |
2564094b | 837 | perfectly with datasource ABC, ODBC driver XYZ, on platform LMN. You may run |
b25ba5b7 | 838 | in to some incompatibilities or unsupported features when moving your |
2564094b JS |
839 | application from one environment to another. But that is what makes |
840 | cross-platform programming fun. It is also pinpoints one of the great | |
841 | things about open source software. It can evolve! | |
b25ba5b7 GT |
842 | |
843 | The most common difference between different database/ODBC driver | |
844 | manufacturers in regards to these wxODBC classes is the lack of | |
2564094b | 845 | standard error codes being returned to the calling program. Sometimes |
b25ba5b7 | 846 | manufacturers have even changed the error codes between versions of |
2564094b | 847 | their databases/drivers. |
b25ba5b7 GT |
848 | |
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 | |
2564094b | 852 | you try to open a table that has not been created yet). Adding support |
b25ba5b7 GT |
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. | |
856 | ||
b25ba5b7 GT |
857 | {\bf Databases} |
858 | ||
859 | Following is a list of known issues and incompatibilities that the | |
2564094b | 860 | wxODBC classes have between different datasources. An up to date |
b25ba5b7 GT |
861 | listing of known issues can be seen in the comments of the source |
862 | for \helpref{wxDb::Dbms}{wxdbdbms}. | |
863 | ||
864 | {\it ORACLE} | |
865 | \begin{itemize}\itemsep=0pt | |
866 | \item Currently the only database supported by the wxODBC classes to support VIEWS | |
867 | \end{itemize} | |
868 | ||
869 | {\it DBASE} | |
870 | ||
2564094b | 871 | NOTE: dBase is not a true ODBC datasource. You only have access to as much |
b25ba5b7 GT |
872 | functionality as the driver can emulate. |
873 | ||
874 | \begin{itemize}\itemsep=0pt | |
509cd921 | 875 | \item Does not support the SQL\_TIMESTAMP structure |
b25ba5b7 | 876 | \item Supports only one cursor and one connect (apparently? with Microsoft driver only?) |
cc81d32f | 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} |
b25ba5b7 GT |
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?? | |
882 | \end{itemize} | |
883 | ||
884 | {\it SYBASE (all)} | |
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 | |
2564094b | 887 | \item Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above |
b25ba5b7 GT |
888 | \end{itemize} |
889 | ||
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 | |
894 | \end{itemize} | |
895 | ||
509cd921 | 896 | {\it mySQL} |
b25ba5b7 GT |
897 | \begin{itemize}\itemsep=0pt |
898 | \item If a column is part of the Primary Key, the column cannot be NULL. | |
cc81d32f | 899 | \item Cannot support selecting for update [\helpref{wxDbTable::CanSelectForUpdate}{wxdbtablecanselectforupdate}]. Always returns false. |
fc2171bd | 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) |
b25ba5b7 GT |
901 | \item Does not support sub-queries in SQL statements |
902 | \end{itemize} | |
903 | ||
904 | {\it POSTGRES} | |
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 | |
908 | \end{itemize} | |
909 | ||
910 | {\it DB2} | |
911 | \begin{itemize}\itemsep=0pt | |
912 | \item Columns which are part of a primary key must be declared as NOT NULL | |
913 | \end{itemize} | |
914 | ||
b25ba5b7 GT |
915 | {\bf UNICODE with wxODBC classes} |
916 | ||
998abc15 GT |
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. | |
b25ba5b7 | 920 | |
49742d4e GT |
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 | |
bb772a8e RN |
923 | use the SQL\_C\_WXCHAR datatype for string columns rather than SQL\_C\_CHAR or |
924 | SQL\_C\_WCHAR. | |
49742d4e | 925 | |
80793cda | 926 | \subsection{wxODBC - Sample Code}\label{wxodbcsamplecode1} |
b25ba5b7 GT |
927 | |
928 | Simplest example of establishing/opening a connection to an ODBC datasource, | |
929 | binding variables to the columns for read/write usage, opening an | |
e31a9900 | 930 | existing table in the datasource, inserting a record, setting query parameters |
b25ba5b7 | 931 | (where/orderBy/from), querying the datasource, reading each row of the |
e31a9900 | 932 | result set, deleting a record, releasing the connection, then cleaning up. |
b25ba5b7 | 933 | |
e31a9900 GT |
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. | |
b25ba5b7 GT |
936 | |
937 | \begin{verbatim} | |
e31a9900 GT |
938 | // ---------------------------------------------------------------------------- |
939 | // HEADERS | |
940 | // ---------------------------------------------------------------------------- | |
941 | #include "wx/log.h" // #included to enable output of messages only | |
942 | #include "wx/dbtable.h" | |
943 | ||
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) | |
951 | { | |
952 | // Retrieve all the error message for the errors that occurred | |
953 | wxString allErrors; | |
954 | if (!pDb == NULL) | |
955 | // Get the database errors and append them to the error message | |
956 | allErrors = wxDbLogExtendedErrorMsg(errmsg.c_str(), pDb, 0, 0); | |
957 | else | |
958 | allErrors = errmsg; | |
959 | ||
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()); | |
965 | fflush(stderr); | |
966 | ||
967 | return 1; | |
968 | } | |
b25ba5b7 | 969 | |
b25ba5b7 | 970 | |
e31a9900 GT |
971 | // ---------------------------------------------------------------------------- |
972 | // entry point | |
973 | // ---------------------------------------------------------------------------- | |
974 | int main(int argc, char **argv) | |
975 | { | |
976 | wxDbConnectInf *DbConnectInf = NULL; // DB connection information | |
b25ba5b7 | 977 | |
e31a9900 | 978 | wxDb *db = NULL; // Database connection |
b25ba5b7 | 979 | |
e31a9900 GT |
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" | |
b25ba5b7 | 985 | |
e31a9900 | 986 | wxString msg; // Used for display messages |
b25ba5b7 | 987 | |
e31a9900 GT |
988 | // ----------------------------------------------------------------------- |
989 | // DEFINE THE CONNECTION HANDLE FOR THE DATABASE | |
990 | // ----------------------------------------------------------------------- | |
991 | DbConnectInf = new wxDbConnectInf(NULL, | |
992 | wxT("CONTACTS-SqlServer"), | |
993 | wxT("sa"), | |
994 | wxT("abk")); | |
9fe17bd3 | 995 | |
e31a9900 | 996 | // Error checking.... |
9fe17bd3 | 997 | if (!DbConnectInf || !DbConnectInf->GetHenv()) |
b25ba5b7 | 998 | { |
e31a9900 GT |
999 | return HandleError(wxT("DB ENV ERROR: Cannot allocate ODBC env handle")); |
1000 | } | |
1001 | ||
b25ba5b7 | 1002 | |
e31a9900 GT |
1003 | // ----------------------------------------------------------------------- |
1004 | // GET A DATABASE CONNECTION | |
1005 | // ----------------------------------------------------------------------- | |
9fe17bd3 | 1006 | db = wxDbGetConnection(DbConnectInf); |
b25ba5b7 | 1007 | |
e31a9900 GT |
1008 | if (!db) |
1009 | { | |
1010 | return HandleError(wxT("CONNECTION ERROR - Cannot get DB connection")); | |
1011 | } | |
1012 | ||
b25ba5b7 | 1013 | |
e31a9900 GT |
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("")); | |
b25ba5b7 | 1019 | // |
2564094b | 1020 | // Bind the columns that you wish to retrieve. Note that there must be |
e31a9900 | 1021 | // 'numTableColumns' calls to SetColDefs(), to match the wxDbTable def |
b25ba5b7 GT |
1022 | // |
1023 | // Not all columns need to be bound, only columns whose values are to be | |
1024 | // returned back to the client. | |
1025 | // | |
e31a9900 | 1026 | table->SetColDefs(0, wxT("FIRST_NAME"), DB_DATA_TYPE_VARCHAR, FirstName, |
998abc15 | 1027 | SQL_C_WXCHAR, sizeof(FirstName), true, true); |
e31a9900 | 1028 | table->SetColDefs(1, wxT("LAST_NAME"), DB_DATA_TYPE_VARCHAR, LastName, |
998abc15 | 1029 | SQL_C_WXCHAR, sizeof(LastName), true, true); |
b25ba5b7 | 1030 | |
b25ba5b7 | 1031 | |
e31a9900 GT |
1032 | // ----------------------------------------------------------------------- |
1033 | // CREATE (or RECREATE) THE TABLE IN THE DATABASE | |
1034 | // ----------------------------------------------------------------------- | |
1035 | if (!table->CreateTable(true)) //NOTE: No CommitTrans is required | |
1036 | { | |
1037 | return HandleError(wxT("TABLE CREATION ERROR: "), table->GetDb()); | |
1038 | } | |
1039 | ||
1040 | ||
1041 | // ----------------------------------------------------------------------- | |
1042 | // OPEN THE TABLE FOR ACCESS | |
1043 | // ----------------------------------------------------------------------- | |
1044 | if (!table->Open()) | |
1045 | { | |
1046 | return HandleError(wxT("TABLE OPEN ERROR: "), table->GetDb()); | |
1047 | } | |
1048 | ||
1049 | ||
1050 | // ----------------------------------------------------------------------- | |
1051 | // INSERT A NEW ROW INTO THE TABLE | |
1052 | // ----------------------------------------------------------------------- | |
1053 | wxStrcpy(FirstName, wxT("JULIAN")); | |
1054 | wxStrcpy(LastName, wxT("SMART")); | |
1055 | if (!table->Insert()) | |
1056 | { | |
1057 | return HandleError(wxT("INSERTION ERROR: "), table->GetDb()); | |
1058 | } | |
1059 | ||
1060 | // Must commit the insert to write the data to the DB | |
1061 | table->GetDb()->CommitTrans(); | |
1062 | ||
1063 | ||
1064 | // ----------------------------------------------------------------------- | |
1065 | // RETRIEVE ROWS FROM THE TABLE BASED ON SUPPLIED CRITERIA | |
1066 | // ----------------------------------------------------------------------- | |
5356f74c | 1067 | // Set the WHERE clause to limit the result set to return |
e31a9900 | 1068 | // all rows that have a value of 'JULIAN' in the FIRST_NAME |
5356f74c | 1069 | // column of the table. |
e31a9900 | 1070 | table->SetWhereClause(wxT("FIRST_NAME = 'JULIAN'")); |
b25ba5b7 GT |
1071 | |
1072 | // Result set will be sorted in ascending alphabetical | |
1073 | // order on the data in the 'LAST_NAME' column of each row | |
e31a9900 | 1074 | table->SetOrderByClause(wxT("LAST_NAME")); |
b25ba5b7 GT |
1075 | |
1076 | // No other tables (joins) are used for this query | |
e31a9900 | 1077 | table->SetFromClause(wxT("")); |
b25ba5b7 GT |
1078 | |
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()) | |
1082 | { | |
e31a9900 | 1083 | return HandleError(wxT("QUERY ERROR: "), table->GetDb()); |
b25ba5b7 GT |
1084 | } |
1085 | ||
e31a9900 GT |
1086 | // Loop through all rows matching the query criteria until |
1087 | // there are no more records to read | |
b25ba5b7 GT |
1088 | while (table->GetNext()) |
1089 | { | |
e31a9900 GT |
1090 | msg.Printf(wxT("Row #%lu -- First Name : %s Last Name is %s"), |
1091 | table->GetRowNum(), FirstName, LastName); | |
1092 | ||
1093 | // Code to display 'msg' here | |
1094 | wxLogMessage(wxT("\n%s\n"), msg.c_str()); | |
b25ba5b7 GT |
1095 | } |
1096 | ||
5356f74c | 1097 | |
e31a9900 GT |
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 | |
5356f74c | 1103 | // |
e31a9900 | 1104 | if (!table->DeleteWhere(wxT("FIRST_NAME = 'JULIAN' and LAST_NAME = 'SMART'"))) |
5356f74c | 1105 | { |
e31a9900 | 1106 | return HandleError(wxT("DELETION ERROR: "), table->GetDb()); |
5356f74c | 1107 | } |
e31a9900 GT |
1108 | |
1109 | // Must commit the deletion to the database | |
5356f74c GT |
1110 | table->GetDb()->CommitTrans(); |
1111 | ||
1112 | ||
e31a9900 GT |
1113 | // ----------------------------------------------------------------------- |
1114 | // TAKE CARE OF THE ODBC CLASS INSTANCES THAT WERE BEING USED | |
1115 | // ----------------------------------------------------------------------- | |
b25ba5b7 | 1116 | // If the wxDbTable instance was successfully created |
5356f74c | 1117 | // then delete it as we are done with it now. |
e31a9900 | 1118 | wxDELETE(table); |
b25ba5b7 | 1119 | |
e31a9900 | 1120 | // Free the cached connection |
b25ba5b7 GT |
1121 | // (meaning release it back in to the cache of datasource |
1122 | // connections) for the next time a call to wxDbGetConnection() | |
1123 | // is made. | |
e31a9900 GT |
1124 | wxDbFreeConnection(db); |
1125 | db = NULL; | |
1126 | ||
b25ba5b7 | 1127 | |
e31a9900 GT |
1128 | // ----------------------------------------------------------------------- |
1129 | // CLEANUP BEFORE EXITING APP | |
1130 | // ----------------------------------------------------------------------- | |
b25ba5b7 GT |
1131 | // The program is now ending, so we need to close |
1132 | // any cached connections that are still being | |
1133 | // maintained. | |
1134 | wxDbCloseConnections(); | |
1135 | ||
1136 | // Release the environment handle that was created | |
1137 | // for use with the ODBC datasource connections | |
e31a9900 | 1138 | wxDELETE(DbConnectInf); |
b25ba5b7 | 1139 | |
e31a9900 GT |
1140 | wxUnusedVar(argc); // Here just to prevent compiler warnings |
1141 | wxUnusedVar(argv); // Here just to prevent compiler warnings | |
1142 | ||
1143 | return 0; | |
1144 | } | |
b25ba5b7 GT |
1145 | \end{verbatim} |
1146 | ||
f7292ebe | 1147 | \subsection{A selection of SQL commands}\label{sqlcommands} |
a660d684 KB |
1148 | |
1149 | The following is a very brief description of some common SQL commands, with | |
1150 | examples. | |
1151 | ||
fa482912 JS |
1152 | \wxheading{See also} |
1153 | ||
1154 | \helpref{Database classes overview}{odbcoverview} | |
1155 | ||
a203f6c0 | 1156 | \subsubsection{Create}\label{odbccreateexample} |
a660d684 KB |
1157 | |
1158 | Creates a table. | |
1159 | ||
1160 | Example: | |
1161 | ||
1162 | \begin{verbatim} | |
1163 | CREATE TABLE Book | |
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) | |
1169 | ) | |
1170 | \end{verbatim} | |
1171 | ||
a203f6c0 | 1172 | \subsubsection{Insert}\label{odbcinsertexample} |
a660d684 KB |
1173 | |
1174 | Inserts records into a table. | |
1175 | ||
1176 | Example: | |
1177 | ||
1178 | \begin{verbatim} | |
1179 | INSERT INTO Book | |
1180 | (BookNumber, CategoryCode, Title) | |
1181 | VALUES(5, 'HR', 'The Lark Ascending') | |
1182 | \end{verbatim} | |
1183 | ||
a203f6c0 | 1184 | \subsubsection{Select}\label{odbcselectexample} |
a660d684 KB |
1185 | |
1186 | The Select operation retrieves rows and columns from a table. The criteria | |
1187 | for selection and the columns returned may be specified. | |
1188 | ||
1189 | Examples: | |
1190 | ||
7af3ca16 | 1191 | {\tt SELECT * FROM Book} |
a660d684 KB |
1192 | |
1193 | Selects all rows and columns from table Book. | |
1194 | ||
7af3ca16 | 1195 | {\tt SELECT Title, RetailPriceAmount FROM Book WHERE RetailPriceAmount > 20.0} |
a660d684 KB |
1196 | |
1197 | Selects columns Title and RetailPriceAmount from table Book, returning only | |
1198 | the rows that match the WHERE clause. | |
1199 | ||
7af3ca16 | 1200 | {\tt SELECT * FROM Book WHERE CatCode = 'LL' OR CatCode = 'RR'} |
a660d684 KB |
1201 | |
1202 | Selects all columns from table Book, returning only | |
1203 | the rows that match the WHERE clause. | |
1204 | ||
7af3ca16 | 1205 | {\tt SELECT * FROM Book WHERE CatCode IS NULL} |
a660d684 KB |
1206 | |
1207 | Selects all columns from table Book, returning only rows where the CatCode column | |
1208 | is NULL. | |
1209 | ||
7af3ca16 | 1210 | {\tt SELECT * FROM Book ORDER BY Title} |
a660d684 KB |
1211 | |
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. | |
1214 | ||
7af3ca16 | 1215 | {\tt SELECT Title FROM Book WHERE RetailPriceAmount >= 20.0 AND RetailPriceAmount <= 35.0} |
a660d684 KB |
1216 | |
1217 | Selects records where RetailPriceAmount conforms to the WHERE expression. | |
1218 | ||
a203f6c0 | 1219 | \subsubsection{Update}\label{odbcupdateexample} |
a660d684 KB |
1220 | |
1221 | Updates records in a table. | |
1222 | ||
1223 | Example: | |
1224 | ||
7af3ca16 | 1225 | {\tt UPDATE Incident SET X = 123 WHERE ASSET = 'BD34'} |
a660d684 KB |
1226 | |
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'. | |
1229 |