tdb.tex
来自「Wxpython Implemented on Windows CE, Sou」· TEX 代码 · 共 1,230 行 · 第 1/4 页
TEX
1,230 行
user has insufficient privileges to even SELECT the table. Other problems
could occur, such as being unable to bind columns, but these other reason
point to some lack of resource (like memory). Any errors generated
internally in the \helpref{wxDbTable::Open}{wxdbtableopen} function are logged to the error log
if SQL logging is turned on for the classes.
{\bf Use the table}
To use the table and the definitions that are now set up, we must first
define what data we want the datasource to collect in to a result set, tell
it where to get the data from, and in which sequence we want the data returned.
\begin{verbatim}
// the WHERE clause limits/specifies which rows in the table
// are to be returned in the result set
table->SetWhereClause("FIRST_NAME = 'GEORGE'");
// Result set will be sorted in ascending alphabetical
// order on the data in the 'LAST_NAME' column of each row
// If the same last name is in the table for two rows,
// sub-sort on the 'AGE' column
table->SetOrderByClause("LAST_NAME, AGE");
// No other tables (joins) are used for this query
table->SetFromClause("");
\end{verbatim}
The above lines will be used to tell the datasource to return in the result
all the rows in the table whose column "FIRST\_NAME" contains the name
'GEORGE' (note the required use of the single quote around the string
literal) and that the result set will return the rows sorted by ascending
last names (ascending is the default, and can be overridden with the
"DESC" keyword for datasources that support it - "LAST\_NAME DESC").
Specifying a blank WHERE clause will result in the result set containing
all rows in the datasource.
Specifying a blank ORDERBY clause means that the datasource will return
the result set in whatever sequence it encounters rows which match the
selection criteria. What this sequence is can be hard to determine.
Typically it depends on the index that the datasource used to find the
rows which match the WHERE criteria. BEWARE - relying on the datasource
to return data in a certain sequence when you have not provided an ORDERBY
clause will eventually cause a problem for your program. Databases can be
tuned to be COST-based, SPEED-based, or some other basis for how it gets
your result set. In short, if you need your result set returned in a
specific sequence, ask for it that way by providing an ORDERBY clause.
Using an ORDERBY clause can be a performance hit, as the database must
sort the items before making the result set available to the client.
Creating efficient indexes that cause the data to be "found" in the correct
ORDERBY sequence can be a big performance benefit. Also, in the large
majority of cases, the database will be able to sort the records faster
than your application can read all the records in (unsorted) and then sort
them. Let the database do the work for you!
Notice in the example above, a column that is not included in the bound
data columns ('AGE') will be used to sub-sort the result set.
The FROM clause in this example is blanked, as we are not going to be
performing any table joins with this simple query. When the FROM clause
is blank, it is assumed that all columns referenced are coming from
the default table for the wxDbTable instance.
After the selection criteria have been specified, the program can now
ask the datasource to perform the search and create a result set that
can be retrieved:
\begin{verbatim}
// Instruct the datasource to perform a query based on the
// criteria specified above in the where/orderBy/from clauses.
if (!table->Query())
{
// An error occurred performing the query
}
\end{verbatim}
Typically, when an error occurs when calling \helpref{wxDbTable::Query}{wxdbtablequery}, it is a
syntax problem in the WHERE clause that was specified. The exact SQL
(datasource-specific) reason for what caused the failure of \helpref{wxDbTable::Query}{wxdbtablequery}
(and all other operations against the datasource can be found by
parsing the table's database connection's "errorList[]" array member for
the stored text of the error.
When the \helpref{wxDbTable::Query}{wxdbtablequery} returns true, the
database was able to successfully complete the requested query using the
provided criteria. This does not mean that there are any rows in the
result set, it just mean that the query was successful.
\normalbox{IMPORTANT: The result created by the call to
\helpref{wxDbTable::Query}{wxdbtablequery} can take one of two forms. It is
either a snapshot of the data at the exact moment that the database
determined the record matched the search criteria, or it is a pointer to
the row that matched the selection criteria. Which form of behavior is
datasource dependent. If it is a snapshot, the data may have changed
since the result set was constructed, so beware if your datasource
uses snapshots and call \helpref{wxDbTable::Refresh}{wxdbtablerefresh}. Most larger brand databases
do not use snapshots, but it is important to mention so that your application
can handle it properly if your datasource does.}
To retrieve the data, one of the data fetching routines must be used to
request a row from the result set, and to store the data from the result
set into the bound memory variables. After \helpref{wxDbTable::Query}{wxdbtablequery}
has completed successfully, the default/current cursor is placed so it
is pointing just before the first record in the result set. If the
result set is empty (no rows matched the criteria), then any calls to
retrieve data from the result set will return false.
\begin{verbatim}
wxString msg;
while (table->GetNext())
{
msg.Printf("Row #%lu -- First Name : %s Last Name is %s",
table->GetRowNum(), FirstName, LastName);
wxMessageBox(msg, "Data", wxOK | wxICON_INFORMATION, NULL);
}
\end{verbatim}
The sample code above will read the next record in the result set repeatedly
until the end of the result set has been reached. The first time that
\helpref{wxDbTable::GetNext}{wxdbtablegetnext} is called right after the successful
call to \helpref{wxDbTable::Query}{wxdbtablequery}, it actually returns the first record
in the result set.
When \helpref{wxDbTable::GetNext}{wxdbtablegetnext} is called and there are
no rows remaining in the result set after the current cursor position,
\helpref{wxDbTable::GetNext}{wxdbtablegetnext} (as well as all the other
wxDbTable::GetXxxxx() functions) will return false.
{\bf Close the table}
When the program is done using a wxDbTable instance, it is as simple as
deleting the table pointer (or if declared statically, letting the
variable go out of scope). Typically the default destructor will take
care of all that is required for cleaning up the wxDbTable instance.
\begin{verbatim}
if (table)
{
delete table;
table = NULL;
}
\end{verbatim}
Deleting a wxDbTable instance releases all of its cursors, deletes the
column definitions and frees the SQL environment handles used by the
table (but not the environment handle used by the datasource connection
that the wxDbTable instance was using).
{\bf Close the datasource connection}
After all tables that have been using a datasource connection have been
closed (this can be verified by calling \helpref{wxDb::GetTableCount}{wxdbgettablecount}
and checking that it returns 0), then you may close the datasource
connection. The method of doing this is dependent on whether the
non-caching or caching method was used to obtain the datasource connection.
If the datasource connection was created manually (non-cached), closing the
connection is done like this:
\begin{verbatim}
if (db)
{
db->Close();
delete db;
db = NULL;
}
\end{verbatim}
If the program used the \helpref{wxDbGetConnection}{wxdbfunctions} function to get a datasource
connection, the following is the code that should be used to free the
connection(s):
\begin{verbatim}
if (db)
{
wxDbFreeConnection(db);
db = NULL;
}
\end{verbatim}
Note that the above code just frees the connection so that it can be
re-used on the next call the \helpref{wxDbGetConnection}{wxdbfunctions}. To actually dispose
of the connection, releasing all of its resources (other than the
environment handle), do the following:
\begin{verbatim}
wxDbCloseConnections();
\end{verbatim}
{\bf Release the ODBC environment handle}
Once all of the connections that used the ODBC environment handle (in
this example it was stored in "DbConnectInf.Henv") have been closed, then
it is safe to release the environment handle:
\begin{verbatim}
DbConnectInf->FreeHenv();
\end{verbatim}
Or, if the long form of the constructor was used and the constructor was allowed
to allocate its own SQL environment handle, leaving scope or destruction of the
wxDbConnectInf will free the handle automatically.
\begin{verbatim}
delete DbConnectInf;
\end{verbatim}
\normalbox{Remember to never release this environment handle if there are any
connections still using the handle.}
\subsection{wxODBC - Known Issues}\label{wxodbcknownissues}
As with creating wxWidgets, writing the wxODBC classes was not the simple
task of writing an application to run on a single type of computer system.
The classes need to be cross-platform for different operating systems, and
they also needed to take in to account different database manufacturers and
different ODBC driver manufacturers. Because of all the possible combinations
of OS/database/drivers, it is impossible to say that these classes will work
perfectly with datasource ABC, ODBC driver XYZ, on platform LMN. You may run
into some incompatibilities or unsupported features when moving your
application from one environment to another. But that is what makes
cross-platform programming fun. It also pinpoints one of the great
things about open source software. It can evolve!
The most common difference between different database/ODBC driver
manufacturers in regards to these wxODBC classes is the lack of
standard error codes being returned to the calling program. Sometimes
manufacturers have even changed the error codes between versions of
their databases/drivers.
In all the tested databases, every effort has been made to determine
the correct error codes and handle them in the class members that need
to check for specific error codes (such as TABLE DOES NOT EXIST when
you try to open a table that has not been created yet). Adding support
for additional databases in the future requires adding an entry for the
database in the \helpref{wxDb::Dbms}{wxdbdbms} function, and then handling any error codes
returned by the datasource that do not match the expected values.
{\bf Databases}
Following is a list of known issues and incompatibilities that the
wxODBC classes have between different datasources. An up to date
listing of known issues can be seen in the comments of the source
for \helpref{wxDb::Dbms}{wxdbdbms}.
{\it ORACLE}
\begin{itemize}\itemsep=0pt
\item Currently the only database supported by the wxODBC classes to support VIEWS
\end{itemize}
{\it DBASE}
NOTE: dBase is not a true ODBC datasource. You only have access to as much
functionality as the driver can emulate.
\begin{itemize}\itemsep=0pt
\item Does not support the SQL\_TIMESTAMP structure
\item Supports only one cursor and one connect (apparently? with Microsoft driver only?)
\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}
\item Table names can only be 8 characters long
\item Column names can only be 10 characters long
\item Currently cannot CREATE a dBase table - bug or limitation of the drivers used??
\item Currently cannot insert rows that have integer columns - bug??
\end{itemize}
{\it SYBASE (all)}
\begin{itemize}\itemsep=0pt
\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
\item Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
\end{itemize}
{\it SYBASE (Enterprise)}
\begin{itemize}\itemsep=0pt
\item If a column is part of the Primary Key, the column cannot be NULL
\item Maximum row size is somewhere in the neighborhood of 1920 bytes
\end{itemize}
{\it mySQL}
\begin{itemize}\itemsep=0pt
\item If a column is part of the Primary Key, the column cannot be NULL.
\item Cannot support selecting for update [\helpref{wxDbTable::CanSelectForUpdate}{wxdbtablecanselectforupdate}]. Always returns false.
\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)
\item Does not support sub-queries in SQL statements
\end{itemize}
{\it POSTGRES}
\begin{itemize}\itemsep=0pt
\item Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
\item Does not support sub-queries in SQL statements
\end{itemize}
{\it DB2}
\begin{itemize}\itemsep=0pt
\item Columns which are part of a primary key must be declared as NOT NULL
\end{itemize}
{\bf UNICODE with wxODBC classes}
As of v2.6 of wxWidgets, the wxODBC classes now fully support the compilation
and use of the classes in a Unicode build of wxWidgets, assuming the compiler
and OS on which the program will be compiled/run is Unicode capable.
The one major difference in writing code that can be compiled in either
unicode or non-unicode builds that is specific to the wxODBC classes is to
use the SQL\_C\_WXCHAR datatype for string columns rather than SQL\_C\_CHAR or
SQL\_C\_WCHAR.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?