I'm thinking I might have made a design mistake in the name of
expediency back in v1.7.10 when I fixed the operator[] overloading
problem.
For those who don't remember the "what and why" of it, the problem was
that Row::operator[] was overloaded for several types of integer, for
const char*, and I think even std::string. Since 0 can be converted to
any of those types implicitly, GCC 3 rightly refused to compile any code
saying something like this:
Row r;
cout << r[0] << ....
GCC also gave ambiguous overload errors for code like this:
cout << r["fred"] ...
since "fred" is a pointer, and thus is convertible to an integer.
So, I removed all but operator[](size_type), added
Row::lookup_by_name(const char*) to handle the string cases, and called
it good.
But recently, it came to me that the integer overloads were probably the
least useful of the bunch in real-world code. Intelligent database
design doesn't make the client code dependent on the number or order of
database columns. So, I wonder if it would have been better to keep
operator[](const char*) instead.
Obviously I can't change it back until v1.8 or v2.0. Keeping that in
mind, my question is, who would it bother if I changed these semantics?
Who uses integer indexes into a Row object in real-world code?
I sure don't, but then, I use the SSQLS mechanism, and it hides the Row
access within its internals. Several of the examples use
Row::operator[](int), but they probably shouldn't, for the intelligent
design reason I gave above.
I've attached a diff of the change you'd need to make to get the library
itself and the examples to compile. Notice that class Row can no longer
derive from the template const_subscript_container, since that demands
that the subclass implement operator[](size_type). That's no doubt why
I chose to keep the overload that I did. It's not a very good reason,
but there it is.
I'd appreciate it if some of you would try this patch, and see how it
affects your code. That will help me to decide if this item even makes
it onto the Wishlist. Also, it would be nice to know what other items
from template const_subscript_container we need to hoist up in to class
Row in order to make real-world code continue to compile. I just
hack-and-slashed it for this proof of concept.
Index: examples/complic1.cpp
===================================================================
RCS file: /usr/local/cvs/mysql++/examples/complic1.cpp,v
retrieving revision 1.2
diff -u -r1.2 complic1.cpp
--- examples/complic1.cpp 1 Mar 2005 03:48:40 -0000 1.2
+++ examples/complic1.cpp 5 Apr 2005 17:04:12 -0000
@@ -43,13 +43,13 @@
// there is a problem in the conversion it will throw an
// exception (caught below). To test it, try changing the
// row[2] to row[0] below.
- cout << setw(17) << row.lookup_by_name("ITEM") <<
- setw(4) << row[1] <<
- setw(7) << double(row[2]) <<
- setw(7) << double(row[3]);
+ cout << setw(17) << row["ITEM"] <<
+ setw(4) << row.col_num(1) <<
+ setw(7) << double(row.col_num(2)) <<
+ setw(7) << double(row.col_num(3));
// The ColData is implicitly converted to a date here.
- Date date = row.lookup_by_name("SDATE");
+ Date date = row["SDATE"];
cout.setf(ios::right);
cout.fill('0');
cout << setw(2) << date.month << "-" << setw(2) <<
Index: examples/dbinfo.cpp
===================================================================
RCS file: /usr/local/cvs/mysql++/examples/dbinfo.cpp,v
retrieving revision 1.2
diff -u -r1.2 dbinfo.cpp
--- examples/dbinfo.cpp 1 Mar 2005 03:48:40 -0000 1.2
+++ examples/dbinfo.cpp 5 Apr 2005 17:04:12 -0000
@@ -106,7 +106,7 @@
for (counter = 0; counter < columns; counter++) {
if (widths[counter]) {
cout << ' ' << setw(widths[counter]) <<
- row[counter] << ' ';
+ row.col_num(counter) << ' ';
}
}
cout << endl;
@@ -130,7 +130,7 @@
for (i = res.begin(); i != res.end(); ++i) {
row = *i;
for (int counter = 0; counter < columns; counter++) {
- cout << row[counter] << " ";
+ cout << row.col_num(counter) << " ";
}
cout << endl;
}
Index: examples/util.cpp
===================================================================
RCS file: /usr/local/cvs/mysql++/examples/util.cpp,v
retrieving revision 1.4
diff -u -r1.4 util.cpp
--- examples/util.cpp 11 Mar 2005 06:08:27 -0000 1.4
+++ examples/util.cpp 5 Apr 2005 17:04:12 -0000
@@ -42,11 +42,11 @@
// Note that you can use either the column index or name to
// retrieve the data.
- cout << setw(20) << row[0].c_str() << ' ' <<
- setw(9) << row[1].c_str() << ' ' <<
- setw(9) << row.lookup_by_name("weight").c_str() << ' ' <<
- setw(9) << row[3].c_str() << ' ' <<
- row[4] << endl;
+ cout << setw(20) << row.col_num(0).c_str() << ' ' <<
+ setw(9) << row.col_num(1).c_str() << ' ' <<
+ setw(9) << row["weight"].c_str() << ' ' <<
+ setw(9) << row.col_num(3).c_str() << ' ' <<
+ row.col_num(4) << endl;
}
}
Index: lib/custom.pl
===================================================================
RCS file: /usr/local/cvs/mysql++/lib/custom.pl,v
retrieving revision 1.14
diff -u -r1.14 custom.pl
--- lib/custom.pl 14 Feb 2005 17:36:32 -0000 1.14
+++ lib/custom.pl 5 Apr 2005 17:04:12 -0000
@@ -221,7 +221,7 @@
$parm_simple2c_b .= ", " unless $j == $i;
$defs .= " T$j I$j;";
$defs .= "\n" unless $j == $i;
- $popul .= " s->I$j = static_cast<T$j>(row[ O$j ]);";
+ $popul .= " s->I$j = static_cast<T$j>(row.col_num( O$j ));";
$popul .= "\n" unless $j == $i;
$names .= " N$j ";
$names .= ",\n" unless $j == $i;
Index: lib/row.cpp
===================================================================
RCS file: /usr/local/cvs/mysql++/lib/row.cpp,v
retrieving revision 1.4
diff -u -r1.4 row.cpp
--- lib/row.cpp 1 Mar 2005 03:29:50 -0000 1.4
+++ lib/row.cpp 5 Apr 2005 17:04:12 -0000
@@ -9,7 +9,7 @@
return res->num_fields();
}
-const ColData Row::operator[] (size_type i) const
+const ColData Row::col_num(size_type i) const
{
if (!initialized) {
if (throw_exceptions)
@@ -21,11 +21,11 @@
return ColData(data.at(i).c_str(), res->types(i), is_nulls[i]);
}
-const ColData Row::lookup_by_name(const char* i) const
+const ColData Row::operator[](const char* i) const
{
int si = res->field_num(std::string(i));
if (si < res->num_fields()) {
- return (*this)[si];
+ return col_num(si);
}
else {
throw BadFieldName(i);
Index: lib/row.h
===================================================================
RCS file: /usr/local/cvs/mysql++/lib/row.h,v
retrieving revision 1.9
diff -u -r1.9 row.h
--- lib/row.h 14 Feb 2005 17:29:54 -0000 1.9
+++ lib/row.h 5 Apr 2005 17:04:12 -0000
@@ -231,8 +231,7 @@
};
//: This class handles the actual rows in an intelligent manner.
-class Row : public const_subscript_container<Row,ColData,const ColData>,
- public RowTemplate<Row, ResUse>
+class Row : public RowTemplate<Row, ResUse>
{
private:
std::vector <std::string> data;
@@ -241,6 +240,8 @@
bool throw_exceptions, initialized;
public:
+ typedef unsigned int size_type;
+
Row() {}
Row(MYSQL_ROW d, const ResUse *r, unsigned long *jj, bool te = false)
: res(r), throw_exceptions(te), initialized(false)
@@ -262,12 +263,12 @@
Row& self() {return *this;}
const ResUse& parent() const {return *res;}
- size_type size() const;
- //: Returns the number of columns.
- const ColData operator [] (size_type i) const;
- //: Returns the value of the field with the index of i.
+ // Returns the number of columns.
+ size_type size() const;
+ // Returns the value of the column named 'col'.
+ const ColData operator [] (const char* col) const;
- const ColData lookup_by_name(const char*) const;
+ const ColData col_num(size_type i) const;
const char *raw_data(int i) const {return data[i].data();}