Author: wyoung
Date: Fri Dec 21 09:42:03 2007
New Revision: 2009
URL: http://svn.gna.org/viewcvs/mysqlpp?rev=2009&view=rev
Log:
Updated the userman to track the Result/ResUse refactoring.
Modified:
trunk/doc/userman/userman.dbx
Modified: trunk/doc/userman/userman.dbx
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/doc/userman/userman.dbx?rev=2009&r1=2008&r2=2009&view=diff
==============================================================================
--- trunk/doc/userman/userman.dbx (original)
+++ trunk/doc/userman/userman.dbx Fri Dec 21 09:42:03 2007
@@ -227,7 +227,7 @@
<para>Not all SQL queries return data. An example
is <command>CREATE TABLE</command>. For these types
of queries, there is a special result type (<ulink
- type="classref" url="ResNSel"/>) that simply reports the
+ type="classref" url="SimpleResult"/>) that simply reports the
state resulting from the query: whether the query was
successful, how many rows it impacted (if any), etc.</para>
</sect3>
@@ -236,31 +236,34 @@
<title>Queries That Return Data: MySQL++ Data
Structures</title>
- <para>The most direct way to retrieve a result set is
- to use <methodname>Query::store()</methodname>. This
- returns a <ulink type="classref" url="Result"/> object
- which acts much like a <classname>std::vector</classname>
- containing one or more <ulink type="classref" url="Row"/>
- objects. In turn, each <classname>Row</classname>
- object is like a <classname>std::vector</classname>
- of <classname>String</classname> objects, one for
- each field in the result set. Therefore, you can treat
- <classname>Result</classname> as a two-dimensional array:
- you can get the 5th field on the 2nd row by simply
- saying <methodname>result[1][4]</methodname>. You can
+ <para>The most direct way to retrieve a result set is to
+ use <methodname>Query::store()</methodname>. This
+ returns a <ulink type="classref"
+ url="StoreQueryResult"/> object, which derives from
+ <classname>std::vector<mysqlpp::Row></classname>,
+ making it a random-access container of <ulink
+ type="classref" url="Row"/>s. In turn,
+ each <classname>Row</classname> object is
+ like a <classname>std::vector</classname> of
+ <classname>String</classname> objects, one for
+ each field in the result set. Therefore, you can
+ treat <classname>StoreQueryResult</classname>
+ as a two-dimensional array: you can get the
+ 5th field on the 2nd row by simply saying
+ <methodname>result[1][4]</methodname>. You can
also access row elements by field name, like this:
<methodname>result[2]["price"]</methodname>.</para>
- <para>A less direct way of working with query results is to
- use <methodname>Query::use()</methodname>, which returns
- a <ulink type="classref" url="ResUse"/> object. This
- class acts like an STL input iterator rather than a
- <classname>std::vector</classname>-like container: you
- walk through your result set one item at a time, always
- going forward. You can't seek around in the result set,
- and you can't know how many results are in the set until
- you find the end. In payment for that inconvenience, you
- get higher memory efficiency, because the entire result
+ <para>A less direct way of working with query results
+ is to use <methodname>Query::use()</methodname>, which
+ returns a <ulink type="classref" url="UseQueryResult"/>
+ object. This class acts like an STL input iterator rather
+ than a <classname>std::vector</classname>: you walk
+ through your result set processing one row at a time,
+ always going forward. You can't seek around in the result
+ set, and you can't know how many results are in the set
+ until you find the end. In payment for that inconvenience,
+ you get better memory efficiency, because the entire result
set doesn't need to be stored in RAM. This is very useful
when you need large result sets.</para>
</sect3>
@@ -466,18 +469,17 @@
<para>This example simply gets the entire "item" column from
the example table, and prints those values out.</para>
- <para>Notice that MySQL++'s <ulink type="classref"
- url="Result"/> and <ulink type="classref"
- url="Row"/> objects work like an array or the STL
- <classname>std::vector</classname> container. The only trick is
- that if you use a variable to subscript one of these objects,
- it must be of type <type>int</type>, or your C++ compiler
- isn't likely to know which overload for <methodname>operator
- []()</methodname> to call. You can avoid this trap by using
- the <methodname>at()</methodname> instead of using the
- subscript operator if you don't mind losing the syntactic
- convenience. It does the same thing, but it isn't overloaded
- like <methodname>operator []()</methodname>.</para>
+ <para>Notice that MySQL++'s <ulink
+ type="classref" url="StoreQueryResult"/> derives
+ from <classname>std::vector</classname>, and <ulink
+ type="classref" url="Row"/> provides an interface that makes
+ it a <classname>vector</classname> work-alike. This means
+ you can access elements with subscript notation, walk through
+ them with iterators, run STL algorithms on them, etc.</para>
+
+ <para><classname>Row</classname> provides a little more in
+ this area than a plain old <classname>vector</classname>: you
+ can also access fields by name using subscript notation.</para>
<para>The only thing that isn't explicit in the code above is
that we delegate command line argument parsing and connection
@@ -1049,26 +1051,38 @@
that do not return data <emphasis>per se</emphasis>. For
instance, <command>CREATE INDEX</command>. You do
get back some information from the MySQL server, which
- <methodname>execute()</methodname> returns to its caller in a
- <ulink type="classref" url="ResNSel"/> object. In addition to
- the obvious — a flag stating whether the query succeeded
- or not — this object also contains things like the
- number of rows that the query affected. If you only need the
- success status, there's <methodname>Query::exec()</methodname>,
- which just returns bool.</para>
+ <methodname>execute()</methodname> returns to its caller
+ in a <ulink type="classref" url="SimpleResult"/> object. In
+ addition to the obvious — a flag stating whether the
+ query succeeded or not — this object also contains things
+ like the number of rows that the query affected. If you only
+ need the success status, it's a little more efficient to call
+ <methodname>Query::exec()</methodname> instead, as it simply
+ returns <type>bool</type>.</para>
<para>If your query does pull data from the database, the
simplest option is <methodname>store()</methodname>. (All
- of the examples up to this point have used this method.)
- This returns a <ulink type="classref" url="Result"/> object,
- which contains the entire result set. The nice thing about
- this is that <classname>Result</classname> is a random-access
- container, like <classname>std::vector</classname>, so you can
- iterate through it forwards and backwards, access elements with
- subscript notation, etc. If you'd rather store the result set
- in an STL container instead of a <classname>Result</classname>
- object, you can use <methodname>storein()</methodname>
- instead.</para>
+ of the examples up to this point have used this
+ method.) This returns a <ulink type="classref"
+ url="StoreQueryResult"/> object, which contains the
+ entire result set. It's especially convenient because
+ <classname>StoreQueryResult</classname> derives from
+ <classname>std::vector<mysqlpp::Row></classname>, so it
+ opens the whole panoply of STL operations for accessing the
+ rows in the result set. Access rows randomly with subscript
+ notation, iterate forwards and backwards over the result set,
+ run STL algorithms on the set...it all works naturally.</para>
+
+ <para>If you like the idea of storing your
+ results in an STL container but don't want to use
+ <classname>std::vector</classname>, you can call
+ <methodname>Query::storein()</methodname> instead. It
+ lets you store the results in any standard STL container
+ (yes, both sequential and set-associative types) instead of
+ using <classname>StoreQueryResult</classname>. You do miss
+ out on some of the additional database information held by
+ <classname>StoreQueryResult</classname>'s other base class,
+ <ulink type="classref" url="ResultBase"/>, however.</para>
<para><methodname>store*()</methodname> queries are convenient,
but the cost of keeping the entire result set in main memory
@@ -1086,8 +1100,8 @@
<para>For these large result sets, the superior option
is a <methodname>use()</methodname> query. This returns
- a <ulink type="classref" url="ResUse"/> object, which is
- similar to <classname>Result</classname>, but without
+ a <ulink type="classref" url="UseQueryResult"/> object, which is
+ similar to <classname>StoreQueryResult</classname>, but without
all of the random-access features. This is because a
"use" query tells the database server to send the results
back one row at a time, to be processed linearly. It's
@@ -1470,8 +1484,8 @@
the same problem. The simplest recipie for disaster is:</para>
<programlisting>
-Result r1 = query.use("select garbage from plink where foobie='tamagotchi'");
-Result r2 = query.use("select blah from bonk where
bletch='smurf'");</programlisting>
+UseQueryResult r1 = query.use("select garbage from plink where
foobie='tamagotchi'");
+UseQueryResult r2 = query.use("select blah from bonk where
bletch='smurf'");</programlisting>
<para>The second <methodname>use()</methodname> call fails
because the first result set hasn't been consumed yet.</para>
@@ -1587,7 +1601,7 @@
to 25 parameters. For example:</para>
<programlisting>
-Result res = query.store("Dinner Rolls", "item", "item",
"price")</programlisting>
+StoreQueryResult res = query.store("Dinner Rolls", "item", "item",
"price")</programlisting>
<para>with the template query provided above would
produce:</para>
@@ -1678,8 +1692,8 @@
<programlisting>
query.template_defaults["field1"] = "item";
query.template_defaults["field2"] = "price";
-Result res1 = query.store("Hamburger Buns", "item");
-Result res2 = query.store(1.25, "price"); </programlisting>
+StoreQueryResult res1 = query.store("Hamburger Buns", "item");
+StoreQueryResult res2 = query.store(1.25, "price"); </programlisting>
<para>This stores the result of the following queries
in <varname>res1</varname> and <varname>res2</varname>,
@@ -1701,7 +1715,7 @@
query.template_defaults["wheref"] = "item";
query.template_defaults["field1"] = "item";
query.template_defaults["field2"] = "price";
-Result res1 = query.store();</programlisting>
+StoreQueryResult res1 = query.store();</programlisting>
<para>This can work, but it is <emphasis>not designed
to</emphasis>. In fact, it's known to fail horribly in one
@@ -1728,7 +1742,7 @@
<programlisting>
query.template_defaults["field1"] = "item";
query.template_defaults["field2"] = "price";
-Result res = query.store(1.25); </programlisting>
+StoreQueryResult res = query.store(1.25); </programlisting>
<para>This would throw <classname>BadParamCount</classname>
because the <varname>wheref</varname> is not specified.</para>
@@ -2654,25 +2668,31 @@
<para>By way of illustration, let me explain a problem we
had up until MySQL++ v3.0. When you issue a database query,
- part of the data you get back in the result set is common
- to all rows in that result set. For example, there's a
- list of what columns are in each row. Since this data is
- the same for each row, older versions of MySQL++ kept this
- information in the <ulink url="Result" type="classref"/>
- object, and each <ulink url="Row" type="classref"/> kept
- a pointer back to the <classname>Result</classname> that
- created it, so it could access this common data at need. This
- is fine as long as each <classname>Result</classname> object
- outlives the <classname>Row</classname> objects it returns,
- which isn't a hardship in a single-threaded program. But
- in a multi-threaded program, there's frequently a desire to
+ part of the data you get back in the result set is common to
+ all rows in that result set. For example, there's a list of
+ what columns are in each row. Since this data is the same
+ for each row in the result set, older versions of MySQL++
+ kept this information in the <classname>Result</classname>
+ object (predecessor to <ulink url="StoreQueryResult"
+ type="classref"/>), and each <ulink url="Row" type="classref"/>
+ kept a pointer back to the <classname>Result</classname> that
+ created it so it could access this common data at need. This
+ was fine as long as each <classname>Result</classname>
+ object outlived the <classname>Row</classname> objects it
+ returned. While you'd have to go out of your way to kill off
+ the <classname>Result</classname> before you were finished with
+ the <classname>Row</classname>s in a typical single-threaded
+ program, in a multi-threaded program it's much easier to get
+ into trouble. For example, there's frequently a desire to
let one connection do the queries, and other threads process
the results. You can see how avoiding lifetime problems here
- would require a careful locking strategy. We got around this
- by giving these shared data structures a lifetime independent
- of the <classname>Result</classname> object that intitially
- creates it, so the last one out could turn off the lights,
- so to speak.</para>
+ would require a careful locking strategy.</para>
+
+ <para>We got around this in MySQL++ v3.0 by giving these
+ shared data structures a lifetime independent of the
+ <classname>StoreQueryResult</classname> object that intitially
+ creates it. These shared data structures stick around until
+ the last object needing them gets destroyed.</para>
<para>Although this is now a solved problem, I bring it up
because there are likely other similar lifetime and sequencing
_______________________________________________
Mysqlpp-commits mailing list
[email protected]
https://mail.gna.org/listinfo/mysqlpp-commits