libtabula

Check-in [ac763fd4ac]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merged mysql-type-info branch into trunk, now that dtest runs to completion on two major platforms and all FIXME comments are dealt with.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ac763fd4acae46551ad7fbba768c6ad6e4d1d5bb
User & Date: tangent 2015-08-14 06:08:39
Context
2015-08-14
06:23
Squished a clang warning about an unused parameter reported on the MySQL++ mailing list by João M. S. Silva. check-in: d076442415 user: tangent tags: trunk
06:08
Merged mysql-type-info branch into trunk, now that dtest runs to completion on two major platforms and all FIXME comments are dealt with. check-in: ac763fd4ac user: tangent tags: trunk
06:05
Merged the contents of a FIXME comment into the relevant Wishlist item. Closed-Leaf check-in: 06939e737d user: tangent tags: mysql-type-info
05:39
Regenerated bmark.txt to remove CRs from cgi_jpeg output now that tests run to completion on OS X. (Earlier success report was on CentOS 5.) check-in: 3fa3f424bf user: tangent tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Wishlist.md.

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
...
141
142
143
144
145
146
147
148
149




150
151
152
153
154
155
156
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
Must Be Done in v4.0
-------------

Items in this section are big or break the library's ABI, so they have
to be done in 4.0, else they must wait for the next allowed ABI breakage
point, 5.0.

*   Reimplement FieldNames in terms of std::map.  At least one test
    shows that the linear scan for field names in row["foo"] is a
    huge time-sink: http://lists.mysql.com/plusplus/9732

*   Reimplement the ostringstream interface in SQLStream, drop the
    inheritance, and include an ostreamstring instance as a member
    instead of deriving from it.  There is some evidence that VC++ has
    problems with dynamic linkage to libraries that export classes
    derived from Standard C++ classes.

    Derive Query from SQLStream instead of std::ostream?
................................................................................
    less likely to be a problem.

*   Convert from Bakefile to CMake.  See the TODO list in the top-level
    `CMakeLists.txt` file.

*   Database independence:

    -   Row remains implemented in terms of MYSQL_ROW.  Need to do some
        kind of pimpl trick here to push that off into the DBDriver.





    -   Field is entirely MySQL-specific.  Rather than pimpl it,
        consider just ripping it out, along with the only other
        users of it, Result::fetch_field*().  All it does is let the
        library user iterate through a thinly-wrapped version of the
        C API's view of the table schema.  That's basically a form
        of reflection, which isn't really a key use case for libtabula.
................................................................................
            }

            template <class DBD = MysqlDriver>
            class UseQueryResult { ...
                DBD::row_type fetch_raw_row();
            }

    -   Tricky bits:

        -   type_info module.  Extremely closely tied to MySQL C API
            right now.  Will probably have to turn it into a parallel
            class hierarchy to DBDriver, or fold it in with same.

        -   Will CMake let us figure out which DB engines are available
            on non-autoconf systems, or at least pass in options that
            let the user select them?

*   If `pkg-config` is available, register ourselves with it using
    information discovered by `configure`.  Also, write out a
    `libtabula-config` script, which either wraps `pkg-config` or
    reinvents it, poorly, for systems that don't have it.

*   Add `String::operator==(const libtabula::null_type&)`.  Needed to







<
<
<
<







 







|
|
>
>
>
>







 







<
<
<
<
<
<
|
|
|







120
121
122
123
124
125
126




127
128
129
130
131
132
133
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
230
231
232
233
234
235
236






237
238
239
240
241
242
243
244
245
246
Must Be Done in v4.0
-------------

Items in this section are big or break the library's ABI, so they have
to be done in 4.0, else they must wait for the next allowed ABI breakage
point, 5.0.





*   Reimplement the ostringstream interface in SQLStream, drop the
    inheritance, and include an ostreamstring instance as a member
    instead of deriving from it.  There is some evidence that VC++ has
    problems with dynamic linkage to libraries that export classes
    derived from Standard C++ classes.

    Derive Query from SQLStream instead of std::ostream?
................................................................................
    less likely to be a problem.

*   Convert from Bakefile to CMake.  See the TODO list in the top-level
    `CMakeLists.txt` file.

*   Database independence:

    -   `Row` remains implemented in terms of `MYSQL_ROW`.  Need to
	    create a `[MySQL]RowImpl` class hierarchy and pass instances
	    of them via the pimpl idiom to `Row` instead of `MYSQL_ROW`.
	    An easy case is `MySQLDriver::fetch_row()`, part of the
	    low-level implementation of "use" queries, but the real
	    trick is doing it for "store" queries.

    -   Field is entirely MySQL-specific.  Rather than pimpl it,
        consider just ripping it out, along with the only other
        users of it, Result::fetch_field*().  All it does is let the
        library user iterate through a thinly-wrapped version of the
        C API's view of the table schema.  That's basically a form
        of reflection, which isn't really a key use case for libtabula.
................................................................................
            }

            template <class DBD = MysqlDriver>
            class UseQueryResult { ...
                DBD::row_type fetch_raw_row();
            }







    -   Will CMake let us figure out which DB engines are available
        on non-autoconf systems, or at least pass in options that
        let the user select them?

*   If `pkg-config` is available, register ourselves with it using
    information discovered by `configure`.  Also, write out a
    `libtabula-config` script, which either wraps `pkg-config` or
    reinvents it, poorly, for systems that don't have it.

*   Add `String::operator==(const libtabula::null_type&)`.  Needed to

Changes to examples/CMakeLists.txt.

1
2
3
4
5
6
7

8
9
10
11
12
13
14
# CMakeLists.txt - Tells CMake how to build the libtabula examples on
#      supported platforms.  See ../CMakeLists.txt for system-wide
#      matters.
#
# Created 2014.08.21 by Warren Young
#
# Copyright © 2014-2015 by Warren Young

# Copyright © 2015 by Educational Technology Resources, Inc.
#
# Others may also hold copyrights on code in this file.  See the
# CREDITS.md file in the top directory of the distribution for details.
#
# This file is part of libtabula.
#







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# CMakeLists.txt - Tells CMake how to build the libtabula examples on
#      supported platforms.  See ../CMakeLists.txt for system-wide
#      matters.
#
# Created 2014.08.21 by Warren Young
#
# Copyright © 2014-2015 by Warren Young
# Copyright © 2015 by Educational Technology Resources, Inc.
# Copyright © 2015 by Educational Technology Resources, Inc.
#
# Others may also hold copyrights on code in this file.  See the
# CREDITS.md file in the top directory of the distribution for details.
#
# This file is part of libtabula.
#

Changes to src/CMakeLists.txt.

47
48
49
50
51
52
53

54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    beemutex.cpp
    cmdline.cpp
    connection.cpp
    cpool.cpp
    datetime.cpp
    dbdriver.cpp
    field_names.cpp

    field_types.cpp
    libtabula.cpp
    manip.cpp
    myset.cpp
    mystring.cpp
    mysql/driver.cpp

    null.cpp
    options.cpp
    qparms.cpp
    query.cpp
    result.cpp
    row.cpp
    scopedconnection.cpp
    sql_buffer.cpp
    sqlstream.cpp
    ssqls2.cpp
    stadapter.cpp
    tcp_connection.cpp
    transaction.cpp
    type_info.cpp
    uds_connection.cpp
    utility.cpp
    vallist.cpp
    wnp_connection.cpp
)
target_link_libraries(tabula ${MYSQL_C_API_LIBRARY})







>






>













<






47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
    beemutex.cpp
    cmdline.cpp
    connection.cpp
    cpool.cpp
    datetime.cpp
    dbdriver.cpp
    field_names.cpp
    field_type.cpp
    field_types.cpp
    libtabula.cpp
    manip.cpp
    myset.cpp
    mystring.cpp
    mysql/driver.cpp
	mysql/ft.cpp
    null.cpp
    options.cpp
    qparms.cpp
    query.cpp
    result.cpp
    row.cpp
    scopedconnection.cpp
    sql_buffer.cpp
    sqlstream.cpp
    ssqls2.cpp
    stadapter.cpp
    tcp_connection.cpp
    transaction.cpp

    uds_connection.cpp
    utility.cpp
    vallist.cpp
    wnp_connection.cpp
)
target_link_libraries(tabula ${MYSQL_C_API_LIBRARY})

Changes to src/field.h.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
 USA
***********************************************************************/

#if !defined(LIBTABULA_FIELD_H)
#define LIBTABULA_FIELD_H

#include "common.h"
#include "type_info.h"

#include <vector>

namespace libtabula {

/// \brief Class to hold information about a SQL field
///
................................................................................

class Field
{
public:
	/// \brief Create empty object
	Field() :
	length_(0),
	max_length_(0),
	flags_(0)
	{
	}

	/// \brief Create object from C API field structure
	Field(const MYSQL_FIELD* pf) :
	name_(pf->name),
	table_(pf->table),
#if MYSQL_VERSION_ID > 40000	// only in 4.0 +
	db_(pf->db),
#endif
	type_(pf->type, (pf->flags & UNSIGNED_FLAG) != 0,
			(pf->flags & NOT_NULL_FLAG) == 0),
	length_(pf->length),
	max_length_(pf->max_length),
	flags_(pf->flags)
	{
	}

	/// \brief Create object as a copy of another Field
	Field(const Field& other) :
	name_(other.name_),
	table_(other.table_),
	db_(other.db_),
	type_(other.type_),
	length_(other.length_),
	max_length_(other.max_length_),
	flags_(other.flags_)
	{
	}

	/// \brief Returns true if field auto-increments
	bool auto_increment() const { return flags_ & AUTO_INCREMENT_FLAG; }

	/// \brief Returns true if field is of some binary type
................................................................................
	/// \brief Return the name of the table the field comes from
	const char* table() const { return table_.c_str(); }

	/// \brief Returns true if field's type is timestamp
	bool timestamp() const { return flags_ & TIMESTAMP_FLAG; }

	/// \brief Return information about the field's type
	const mysql_type_info& type() const { return type_; }

	/// \brief Returns true if field is part of a unique key
	bool unique_key() const { return flags_ & UNIQUE_KEY_FLAG; }

	/// \brief Returns true if field has the zerofill attribute
	bool zerofill() const { return flags_ & ZEROFILL_FLAG; }

private:
	std::string name_;		///< the field's name
	std::string table_;		///< name of table field comes from
	std::string db_;		///< name of database field comes from
	mysql_type_info type_;	///< info about the field's type
	size_t length_;			///< creation size of column
	size_t max_length_;		///< size of largest item in column in result set
	unsigned int flags_;	///< DB engine-specific set of bit flags
};


/// \brief The list-of-Fields type
typedef std::vector<Field> Fields;

} // end namespace libtabula

#endif // !defined(LIBTABULA_FIELD_H)







|







 







|
<










|
<

|
<










|
<







 







|











|












24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
63

64
65

66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
 USA
***********************************************************************/

#if !defined(LIBTABULA_FIELD_H)
#define LIBTABULA_FIELD_H

#include "common.h"
#include "mysql/ft.h"

#include <vector>

namespace libtabula {

/// \brief Class to hold information about a SQL field
///
................................................................................

class Field
{
public:
	/// \brief Create empty object
	Field() :
	length_(0),
	max_length_(0)

	{
	}

	/// \brief Create object from C API field structure
	Field(const MYSQL_FIELD* pf) :
	name_(pf->name),
	table_(pf->table),
#if MYSQL_VERSION_ID > 40000	// only in 4.0 +
	db_(pf->db),
#endif
	type_(MySQLFieldType(pf->type, pf->flags)),

	length_(pf->length),
	max_length_(pf->max_length)

	{
	}

	/// \brief Create object as a copy of another Field
	Field(const Field& other) :
	name_(other.name_),
	table_(other.table_),
	db_(other.db_),
	type_(other.type_),
	length_(other.length_),
	max_length_(other.max_length_)

	{
	}

	/// \brief Returns true if field auto-increments
	bool auto_increment() const { return flags_ & AUTO_INCREMENT_FLAG; }

	/// \brief Returns true if field is of some binary type
................................................................................
	/// \brief Return the name of the table the field comes from
	const char* table() const { return table_.c_str(); }

	/// \brief Returns true if field's type is timestamp
	bool timestamp() const { return flags_ & TIMESTAMP_FLAG; }

	/// \brief Return information about the field's type
	const FieldType& type() const { return type_; }

	/// \brief Returns true if field is part of a unique key
	bool unique_key() const { return flags_ & UNIQUE_KEY_FLAG; }

	/// \brief Returns true if field has the zerofill attribute
	bool zerofill() const { return flags_ & ZEROFILL_FLAG; }

private:
	std::string name_;		///< the field's name
	std::string table_;		///< name of table field comes from
	std::string db_;		///< name of database field comes from
	FieldType type_;		///< info about the field's type
	size_t length_;			///< creation size of column
	size_t max_length_;		///< size of largest item in column in result set
	unsigned int flags_;	///< DB engine-specific set of bit flags
};


/// \brief The list-of-Fields type
typedef std::vector<Field> Fields;

} // end namespace libtabula

#endif // !defined(LIBTABULA_FIELD_H)

Added src/field_type.cpp.

































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/***********************************************************************
 field_type.cpp - Implements the FieldType class, as well as some
 	internal helper classes.

 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2007, 2014-2015 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "common.h"
#include "field_type.h"

#include "datetime.h"
#include "myset.h"
#include "sql_types.h"

#include <string>

using namespace std;

namespace libtabula {

#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.

// This table maps generic C++ type information to libtabula specific
// type information.  It is part of the transformation that allows
// plain C++ data types to map to driver-specific data types.
//
// The second half of the table parallels the first, to handle null-able
// versions of the types in the first half.  This is required because
// SQL's 'null' concept does not map neatly into the C++ type system, so
// null-able versions of these types have to have a different C++ type,
// implemented using the Null template.  See null.h for further details.
//
// This mapping is lossy.  There is one entry for every \c sql_* data type
// defined in libtabula, but it maps to a non-unique {Base, Flag} pair.
// 
// Because the converse is also true -- a given {Base, Flag} pair could
// map to any of several libtabula data types -- we have the notion of a
// "best" conversion, which yields the most likely C++ data type for a
// given pair.  This lossiness matters most with numeric data types,
// where there may be multiple sizes.  We use the largest "native" size.
// 
// This table does not necessarily honor fine type distinctions made at
// the DBMS layer.  For example, we paper over the UNSIGNED FLOAT mess.
//
// This table is inverted for reverse lookup as the static type_map_
// object.
typedef detail::AnnotatedFT AFT;
static const AFT types_[] = {
	// Basic non-nullable type set
	AFT("TINYINT NOT NULL", typeid(sql_tinyint),
			FieldType::ft_integer, FieldType::tf_default, false),
	AFT("TINYINT UNSIGNED NOT NULL", typeid(sql_tinyint_unsigned),
			FieldType::ft_integer, FieldType::tf_unsigned, false),
	AFT("SMALLINT NOT NULL", typeid(sql_smallint),
			FieldType::ft_integer, FieldType::tf_default, false),
	AFT("SMALLINT UNSIGNED NOT NULL", typeid(sql_smallint_unsigned),
			FieldType::ft_integer, FieldType::tf_unsigned, false),
	AFT("MEDIUMINT NOT NULL", typeid(sql_mediumint),
			FieldType::ft_integer, FieldType::tf_unsigned, false),
	AFT("MEDIUMINT UNSIGNED NOT NULL", typeid(sql_mediumint_unsigned),
			FieldType::ft_integer, FieldType::tf_unsigned, false),
	AFT("INT NOT NULL", typeid(sql_int), FieldType::ft_integer),
	AFT("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned),
			FieldType::ft_integer, FieldType::tf_unsigned),
	AFT("BIGINT NOT NULL", typeid(sql_bigint), 
			FieldType::ft_integer, FieldType::tf_default, false),
	AFT("BIGINT UNSIGNED NOT NULL", typeid(sql_bigint_unsigned),
			FieldType::ft_integer, FieldType::tf_unsigned, false),
	AFT("FLOAT NOT NULL", typeid(sql_float), 
			FieldType::ft_real, FieldType::tf_default, false),
	AFT("FLOAT UNSIGNED NOT NULL", typeid(sql_float),
			FieldType::ft_real, FieldType::tf_unsigned, false),
	AFT("DOUBLE NOT NULL", typeid(sql_double), FieldType::ft_real),
	AFT("DOUBLE UNSIGNED NOT NULL", typeid(sql_double),
			FieldType::ft_real, FieldType::tf_unsigned),
	AFT("DECIMAL NOT NULL", typeid(sql_decimal), FieldType::ft_decimal),
	AFT("TIMESTAMP NOT NULL", typeid(sql_timestamp), FieldType::ft_timestamp),
	AFT("DATE NOT NULL", typeid(sql_date), FieldType::ft_date),
	AFT("TIME NOT NULL", typeid(sql_time), FieldType::ft_time),
	AFT("DATETIME NOT NULL", typeid(sql_datetime), FieldType::ft_datetime),
	AFT("ENUM NOT NULL", typeid(sql_enum), FieldType::ft_enum),
	AFT("SET NOT NULL", typeid(sql_set), FieldType::ft_set),
	AFT("TINYBLOB NOT NULL", typeid(sql_tinyblob),
			FieldType::ft_blob, FieldType::tf_default, false),
	AFT("MEDIUMBLOB NOT NULL", typeid(sql_mediumblob), 
			FieldType::ft_blob, FieldType::tf_default, false),
	AFT("LONGBLOB NOT NULL", typeid(sql_longblob),
			FieldType::ft_blob, FieldType::tf_default, false),
	AFT("BLOB NOT NULL", typeid(sql_blob), FieldType::ft_blob),
	AFT("VARCHAR NOT NULL", typeid(sql_varchar), FieldType::ft_text),
	AFT("CHAR NOT NULL", typeid(sql_char), 
			FieldType::ft_text, FieldType::tf_default, false),
	AFT("NULL NOT NULL", typeid(void),
			FieldType::ft_null, FieldType::tf_default),

	// Nullable versions of above
	AFT("TINYINT NULL", typeid(Null<sql_tinyint>),
			FieldType::ft_integer, FieldType::tf_null, false),
	AFT("TINYINT UNSIGNED NULL", typeid(Null<sql_tinyint_unsigned>),
			FieldType::ft_integer,
			FieldType::tf_null | FieldType::tf_unsigned, false),
	AFT("SMALLINT NULL", typeid(Null<sql_smallint>),
			FieldType::ft_integer, FieldType::tf_null, false),
	AFT("SMALLINT UNSIGNED NULL", typeid(Null<sql_smallint_unsigned>),
			FieldType::ft_integer,
			FieldType::tf_null | FieldType::tf_unsigned, false),
	AFT("MEDIUMINT NULL", typeid(Null<sql_mediumint>),
			FieldType::ft_integer, FieldType::tf_null, false),
	AFT("MEDIUMINT UNSIGNED NULL", typeid(Null<sql_mediumint_unsigned>), 
			FieldType::ft_integer,
			FieldType::tf_null | FieldType::tf_unsigned, false),
	AFT("INT NULL", typeid(Null<sql_int>),
			FieldType::ft_integer, FieldType::tf_null),
	AFT("INT UNSIGNED NULL", typeid(Null<sql_int_unsigned>),
			FieldType::ft_integer, FieldType::tf_null | FieldType::tf_unsigned),
	AFT("BIGINT NULL", typeid(Null<sql_bigint>),
			FieldType::ft_integer, FieldType::tf_null, false),
	AFT("BIGINT UNSIGNED NULL", typeid(Null<sql_bigint_unsigned>),
			FieldType::ft_integer,
			FieldType::tf_null | FieldType::tf_unsigned, false),
	AFT("FLOAT NULL", typeid(Null<sql_float>),
			FieldType::ft_real, FieldType::tf_null, false),
	AFT("FLOAT UNSIGNED NULL", typeid(Null<sql_float>),
			FieldType::ft_real,
			FieldType::tf_null | FieldType::tf_unsigned, false),
	AFT("DOUBLE NULL", typeid(Null<sql_double>),
			FieldType::ft_real, FieldType::tf_null),
	AFT("DOUBLE UNSIGNED NULL", typeid(Null<sql_double>),
			FieldType::ft_real, FieldType::tf_null | FieldType::tf_unsigned),
	AFT("DECIMAL NULL", typeid(Null<sql_decimal>),
			FieldType::ft_decimal, FieldType::tf_null),
	AFT("TIMESTAMP NULL", typeid(Null<sql_timestamp>),
			FieldType::ft_timestamp),
	AFT("DATE NULL", typeid(Null<sql_date>),
			FieldType::ft_date, FieldType::tf_null),
	AFT("TIME NULL", typeid(Null<sql_time>),
			FieldType::ft_time, FieldType::tf_null),
	AFT("DATETIME NULL", typeid(Null<sql_datetime>),
			FieldType::ft_datetime, FieldType::tf_null),
	AFT("ENUM NULL", typeid(Null<sql_enum>),
			FieldType::ft_enum, FieldType::tf_null),
	AFT("SET NULL", typeid(Null<sql_set>),
			FieldType::ft_set, FieldType::tf_null),
	AFT("TINYBLOB NULL", typeid(Null<sql_tinyblob>),
			FieldType::ft_blob, FieldType::tf_null, false),
	AFT("MEDIUMBLOB NULL", typeid(Null<sql_mediumblob>),
			FieldType::ft_blob, FieldType::tf_null, false),
	AFT("LONGBLOB NULL", typeid(Null<sql_longblob>),
			FieldType::ft_blob, FieldType::tf_null, false),
	AFT("BLOB NULL", typeid(Null<sql_blob>),
			FieldType::ft_blob, FieldType::tf_null),
	AFT("VARCHAR NULL", typeid(Null<sql_varchar>),
			FieldType::ft_text, FieldType::tf_null),
	AFT("CHAR NULL", typeid(Null<sql_char>),
			FieldType::ft_text, FieldType::tf_null, false),
	AFT("NULL NOT NULL", typeid(Null<void>),
			FieldType::ft_null, FieldType::tf_default),
};

// Number of elements in types_[]
static const int num_types_ = sizeof(types_) / sizeof(types_[0]);


// Set up an "index" into types_[] keyed on std::type_info, to make
// the FieldType(type_info) conversion ctor faster.
class TypeMap
{
private:
	struct Cmp
	{
		bool operator() (const type_info* lhs, const type_info* rhs) const
				{ return lhs < rhs; }
	};
	typedef map<const type_info*, size_t, Cmp> map_type;

	map_type map_;

public:
	TypeMap()
	{
		for (map_type::mapped_type i = 0; i < num_types_; ++i) {
			map_[types_[i].c_type_] = i;
		}
	}
	const map_type::mapped_type operator [](const type_info& ti) const
	{
		// Try for an exact match on the C++ std::type_info value
		map_type::const_iterator it = map_.find(&ti);
		if (it != map_.end()) {
			return it->second;
		}
		else {
			// Can't find it.  Caller must be passing a C++ data type
			// that simply isn't represented in the types_ array.  Wah.
			ostringstream outs;
			outs << "Failed to find libtabula type info for " << ti.name();
			throw TypeLookupFailed(outs.str());
		}
	}
};
static const TypeMap type_map_;


// std::type_info conversion ctor.  Looks up the statically-defined
// libtabula type info in types_[] and copies that.
FieldType::FieldType(const type_info& t)
{
	size_t i = type_map_[t];
	base_type_ = types_[i].base_type_;
	flags_ = types_[i].flags_;
}


// "Annotate" this type by looking up the C++ and SQL type info in the
// types_[] table based on our libtabula {Base,Flags} pair.
const AFT&
FieldType::annotate() const
{
	// Make sure we got fully-initted first.
	if (base_type_ == ft_unsupported) {
		throw TypeLookupFailed("FieldType::annotate() called before "
				"object fully initted");
	}

	// Try to find an entry in types_[] matching our {Base,Flags} pair
	int guess = -1;
	for (size_t i = 0; i < num_types_; ++i) {
		const AFT& cand = types_[i];
		if (base_type_ == cand.base_type_) {
			// Found a possible match.
			if (flags_ == cand.flags_) {
				// It's a good match, but is it the best?
				guess = i;
				if (cand.best_guess_) return cand;
			}
			else if ((cand.flags_ & flags_) == cand.flags_) {
				// All flags on the candidate are present in the
				// caller's value, so keep this one in mind, but
				// don't go with it unless we find no better option.
				guess = i;
			}
			// else, it's only a weak match; hold out for better
		}
	}

	// Did we find one?
	if (guess >= 0) {
		return types_[guess];
	}
	else {
		ostringstream outs;
		outs << "Failed to find C++ and SQL type info for libtabula "
				"type {" << base_type_ << ',' << flags_ << '}';
		throw TypeLookupFailed(outs.str());
	}
}


// Pass calls down to our equivalent AnnotatedFT object
const char* FieldType::name() const { return annotate().c_type_->name(); }
const char* FieldType::sql_name() const { return annotate().sql_name_; }
const std::type_info& FieldType::c_type() const { return *annotate().c_type_; }

#endif // !defined(DOXYGEN_IGNORE)

} // end namespace libtabula

Added src/field_type.h.









































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/// \file field_type.h
/// \brief Declares the FieldType class, which provides a translation
/// between the SQL and C++ type systems.
///
/// This class should be treated as an internal implementation detail.
/// End user code should not have to use this class directly.  The
/// library uses this information to translate C++ type info to and
/// from the DBMS layer, so if you are using appropriate C++ types,
/// the translation to/from the appropriate FieldType should be
/// transparent.  If not, consider it a bug, and report it.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2008, 2014-2015 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#if !defined(LIBTABULA_FIELD_TYPE_H)
#define LIBTABULA_FIELD_TYPE_H

#include "common.h"
#include "exceptions.h"

#include <map>
#include <sstream>
#include <typeinfo>

namespace libtabula {

namespace detail {
	class AnnotatedFT;
}

/// \brief SQL field type information
///
/// \internal Used within libtabula for mapping SQL types to C++ types
/// and vice versa.
class LIBTABULA_EXPORT FieldType
{
public:
	/// \brief Basic SQL data types with libtabula support
	/// 
	/// These are ordered roughly by commonality in SQL implementations.
	/// As you go further down the list, the chance decreases that any
	/// given SQL DBMS supports it.
	///
	/// This is called FieldType::Base because these are the basic data
	/// types only, without modifiers.  See FieldType::Flag.
	enum Base {
		// Special data type, giving libtabula a way to flag data of a
		// type that the library itself does not support.
		ft_unsupported,

		// Data types pretty much every SQL implementation knows
		ft_null,		// data type of SQL NULL values; not used as col type!
		ft_integer,
		ft_real,		// a.k.a float, double...
		ft_text,
		ft_blob,

		// Common data types, but not universal.  For example, SQLite
		// only supports date/time values via specially-formatted string
		// columns.  For another, many DBMSes have no formal "boolean"
		// type, but instead require you to use bare integers or enums.
		ft_date = 20,		// skip a bit to allow expansion
		ft_time,
		ft_datetime,
		ft_timestamp,
		ft_decimal,			// fixed-point number; not same as ft_real!
		ft_enum,
		ft_boolean,
		ft_set,
	};

	/// \brief SQL data type modifier flags
	///
	/// These flags modify the \c ft_* type flag enum.  If this field
	/// has no flags (i.e. it is tf_default) it is implicitly signed
	/// if it's an integer type, and it's non-null in all cases.
	///
	/// As with Base, these are ordered by commonality.
	enum Flag {
		// Type modifiers every SQL DBMS should support, even SQLite
		tf_default = 		1 << 0,
		tf_unsigned = 		1 << 1,
		tf_null = 			1 << 2,

		// Common type attributes, but not universal
		tf_primary_key =	1 << 10,
		tf_unique_key =		1 << 11,
		tf_multiple_key =	1 << 12,

		// Nonstandard modifers; mainly MySQL-specific
		tf_auto_increment = 1 << 20,	// nonstandard SQL
		tf_binary = 		1 << 21,	// BINARY TEXT ≅ CHAR sans encoding
		tf_zerofill =		1 << 22,	// 0-padded strings
	};

	/// \brief Standard constructor
	///
	/// Although this ctor allows you to use it as a default ctor,
	/// we only support that because FieldTypes keeps a vector of these
	/// objects, and std::vector requires a default ctor for its
	/// elements.  If you are creating these objects in code you write,
	/// you need to pass the first parameter at least, or overwrite the
	/// default-initted copy with the assignment operator.  Failure to
	/// do so will cause a runtime error.
	FieldType(Base b = ft_unsupported, unsigned int f = tf_default) :
	base_type_(b),
	flags_(f)
	{
	}

	/// \brief Create object as a copy of another
	FieldType(const FieldType& other) :
	base_type_(other.base_type_),
	flags_(other.flags_)
	{
	}

	/// \brief Create a FieldType object from a C++ type_info object
	///
	/// This tries to map a C++ type to the closest libtabula data type.
	/// It is necessarily somewhat approximate.  For one thing, we
	/// ignore integer signedness.  We also make the fully-warranted
	/// assumption that C++ hasn't grown a SQL-like "nullable" type
	/// attribute between the time this code was written and the time
	/// your compiler was last improved.
	FieldType(const std::type_info& t);

	/// \brief Assign another FieldType object to this object
	FieldType& operator =(const FieldType& t)
	{
		base_type_ = t.base_type_;
		flags_ = t.flags_;
		return *this;
	}

	/// \brief Returns the libtabula data type enum for this object.
	///
	/// Our return value may simply be the Base value we got in our
	/// ctor, but it could also be a conversion from another form,
	/// either C++ type info via our std::type_info ctor or C DBMS
	/// API type info from a subclass ctor.
	///
	/// This does not encode null-ness.
	const Base base_type() const { return base_type_; }

	/// \brief Returns true if this type describes a SQL column with a
	/// default value.
	///
	/// Always returns false if the object is storing information about
	/// a SQL value on a particular row, rather than column info.
	bool is_default() const { return flags_ == FieldType::tf_default; }

	/// \brief Returns true if this type describes either a null-able SQL
	/// column or a SQL value that is NULL.
	bool is_null() const { return flags_ & FieldType::tf_null; }

	/// \brief Returns true if this type describes an SQL column that
	/// cannot be negative.
	///
	/// Various SQL DBMSes interpret this differently.  Some don't have
	/// a strong notion of unsigned-ness (e.g. SQLite) while others take
	/// the concept rather too far (IMHO) allowing perversions like
	/// "unsigned float." (e.g. MySQL/MariaDB)
	bool is_unsigned() const { return flags_ & FieldType::tf_unsigned; }

	/// \brief Returns an implementation-defined name of the C++ type.
	///
	/// Returns the name that would be returned by typeid().name() for
	/// the C++ type associated with the SQL type.
	const char* name() const;

	/// \brief Returns the name of the SQL type.
	///
	/// Returns the SQL name for the type.
	const char* sql_name() const;

	/// \brief Returns the type_info for the C++ type associated with
	/// the SQL type.
	///
	/// Returns the C++ type_info record corresponding to the SQL type.
	const std::type_info& c_type() const;

	/// \brief Returns true if the SQL type is of a type that needs to
	/// be quoted for syntactically correct SQL.
	bool quote_q() const
	{
		return	base_type_ == ft_blob ||
				base_type_ == ft_date ||
				base_type_ == ft_datetime ||
				base_type_ == ft_set ||
				base_type_ == ft_text ||
				base_type_ == ft_time;
	}

	/// \brief Returns true if the SQL type is of a type that needs to
	/// be escaped for syntactically correct SQL.
	bool escape_q() const
	{
		return	base_type_ == ft_blob ||
				base_type_ == ft_enum ||
				base_type_ == ft_text;
	}

	/// \brief Return an opaque composite value that uniquely identifies
	/// this field type.
	///
	/// Though the implementation is right here to be examined, do not
	/// depend on the format of the value.  It could change.
	unsigned short id() const { return (flags_ << 8) | base_type_; }

private:
	//// Internal support functions
	const detail::AnnotatedFT& annotate() const;

	//// Internal data
	Base base_type_;
	unsigned int flags_;
};

namespace detail {
	/// \brief An extension of FieldType, adding several values that are
	/// implicitly associated with our parent's {Base, Flag} pair.
	///
	/// \internal This type is not for use by end-user code.  It is
	/// public only because libtabula creates a static array of these
	/// for use by FieldType to use in various lookups.
	class AnnotatedFT : public FieldType
	{
	public:
		AnnotatedFT& operator=(const AnnotatedFT& other);
		
		// Parameter order differs from FieldType's ctor on purpose:
		// they're ordered to allow some to default in many cases in
		// the types_[] table initialization.
		AnnotatedFT(const char* s, const std::type_info& t,
				Base bt, unsigned int f = tf_default, bool bg = true) :
		FieldType(bt, f),
		sql_name_(s),
		c_type_(&t),
		best_guess_(bg)
		{
		}

		const char* sql_name_;
		const std::type_info* c_type_;
		const bool best_guess_;
	};
} // end namespace libtabula::detail

/// \brief Returns true if two FieldType objects are equal.
inline bool operator ==(const FieldType& lhs, const FieldType& rhs)
{
	return lhs.id() == rhs.id();
}

/// \brief Returns true if two FieldType objects are not equal.
inline bool operator !=(const FieldType& lhs, const FieldType& rhs)
{
	return lhs.id() != rhs.id();
}

/// \brief Returns true if a given FieldType object is equal
/// to a given C++ type_info object.
inline bool operator ==(const std::type_info& lhs, const FieldType& rhs)
{
	return lhs == rhs.c_type();
}

/// \brief Returns true if a given FieldType object is not equal
/// to a given C++ type_info object.
inline bool operator !=(const std::type_info& lhs, const FieldType& rhs)
{
	return lhs != rhs.c_type();
}

/// \brief Returns true if a given FieldType object is equal
/// to a given C++ type_info object.
inline bool operator ==(const FieldType& lhs, const std::type_info& rhs)
{
	return lhs.c_type() == rhs;
}

/// \brief Returns true if a given FieldType object is not equal
/// to a given C++ type_info object.
inline bool operator !=(const FieldType& lhs, const std::type_info& rhs)
{
	return lhs.c_type() != rhs;
}

/// \brief Returns true if the lhs FieldType object is "less than" the
/// rhs object, for sorting purposes.
///
/// This only exists to allow you to use FieldType in associative
/// containers.  There is no other meaning to the ordering.
inline bool operator <(const FieldType& lhs, const FieldType& rhs)
{
	return lhs.id() < rhs.id();
}

} // end namespace libtabula

#endif // !defined(LIBTABULA_FIELD_TYPE_H)

Changes to src/field_types.h.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#ifndef LIBTABULA_FIELD_TYPES_H
#define LIBTABULA_FIELD_TYPES_H

#include "type_info.h"

#include <vector>

namespace libtabula {

#if !defined(DOXYGEN_IGNORE)
// Make Doxygen ignore this
class LIBTABULA_EXPORT ResultBase;
#endif

/// \brief A vector of SQL field types.
class FieldTypes : public std::vector<mysql_type_info>
{
public:
	/// \brief Default constructor
	FieldTypes() { }
	
	/// \brief Create list of field types from a result set
	FieldTypes(const ResultBase* res)
	{
		init(res);
	}

	/// \brief Create fixed-size list of uninitialized field types
	FieldTypes(int i) :
	std::vector<mysql_type_info>(i)
	{
	}

	/// \brief Initialize field list based on a result set
	FieldTypes& operator =(const ResultBase* res)
	{
		init(res);
................................................................................

	/// \brief Insert a given number of uninitialized field type
	/// objects at the beginning of the list
	///
	/// \param i number of field type objects to insert
	FieldTypes& operator =(int i)
	{
		insert(begin(), i, mysql_type_info());
		return *this;
	}

private:
	void init(const ResultBase* res);
};

} // end namespace libtabula

#endif







|











|













|







 







|










24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#ifndef LIBTABULA_FIELD_TYPES_H
#define LIBTABULA_FIELD_TYPES_H

#include "field_type.h"

#include <vector>

namespace libtabula {

#if !defined(DOXYGEN_IGNORE)
// Make Doxygen ignore this
class LIBTABULA_EXPORT ResultBase;
#endif

/// \brief A vector of SQL field types.
class FieldTypes : public std::vector<FieldType>
{
public:
	/// \brief Default constructor
	FieldTypes() { }
	
	/// \brief Create list of field types from a result set
	FieldTypes(const ResultBase* res)
	{
		init(res);
	}

	/// \brief Create fixed-size list of uninitialized field types
	FieldTypes(int i) :
	std::vector<FieldType>(i)
	{
	}

	/// \brief Initialize field list based on a result set
	FieldTypes& operator =(const ResultBase* res)
	{
		init(res);
................................................................................

	/// \brief Insert a given number of uninitialized field type
	/// objects at the beginning of the list
	///
	/// \param i number of field type objects to insert
	FieldTypes& operator =(int i)
	{
		insert(begin(), i, FieldType());
		return *this;
	}

private:
	void init(const ResultBase* res);
};

} // end namespace libtabula

#endif

Changes to src/libtabula.h.in.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
51
52
53
54
55
56
57

58
59
60
61
62
63
64
/// is a strictly optional feature of libtabula.
///
/// There is no point in trying to optimize which headers you include,
/// because the libtabula headers are so intertwined.  You can only get
/// trivial compile time benefits, at the expense of clarity.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2010 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS.txt file
 in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................
/// actual library you're linking to.
#define LIBTABULA_HEADER_VERSION LIBTABULA_VERSION(@LIBTABULA_VERSION_MAJOR@, @LIBTABULA_VERSION_MINOR@, @LIBTABULA_VERSION_BUGFIX@)

// This #include order gives the fewest redundancies in the #include
// dependency chain.
#include "connection.h"
#include "cpool.h"

#include "query.h"
#include "scopedconnection.h"
#include "sql_types.h"
#include "transaction.h"

namespace libtabula {








|
|
|
|







 







>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/// is a strictly optional feature of libtabula.
///
/// There is no point in trying to optimize which headers you include,
/// because the libtabula headers are so intertwined.  You can only get
/// trivial compile time benefits, at the expense of clarity.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2010, 2014 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................
/// actual library you're linking to.
#define LIBTABULA_HEADER_VERSION LIBTABULA_VERSION(@LIBTABULA_VERSION_MAJOR@, @LIBTABULA_VERSION_MINOR@, @LIBTABULA_VERSION_BUGFIX@)

// This #include order gives the fewest redundancies in the #include
// dependency chain.
#include "connection.h"
#include "cpool.h"
#include "field_type.h"
#include "query.h"
#include "scopedconnection.h"
#include "sql_types.h"
#include "transaction.h"

namespace libtabula {

Changes to src/mysql/driver.h.

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
320
321
322
323
324
325
326



327
328
329
330
331
332
333
334
335
336
337
338
		rows_(rows)
		{
		}

		~ResultImpl() { /* implicit mysql_free_result(res_.raw()) */  }
		operator MYSQL_RES*() const { return res_.raw(); }

		// FIXME: Do we still need this?  Can't see who calls it.
		ResultImpl* clone() const
		{
			return new ResultImpl(res_, rows());
		}

		size_t rows() const { return rows_; }

	private:
		// Has to be mutable because so many Connector/C APIs take
		// non-const MYSQL_RES*, and we call those from const methods.
		mutable RefCountedPointer<MYSQL_RES> res_;

................................................................................

	/// \brief Returns the next DB row from the given result set.
	///
	/// Wraps \c mysql_fetch_row() in MySQL C API.
	Row fetch_row(ResultBase& res, ResultBase::Impl& impl)
	{
		if (MYSQL_ROW raw = mysql_fetch_row(MYSQL_RES_FROM_IMPL(impl))) {
			// FIXME: Create MySQLRowImpl here from MYSQL_ROW, and
			//        make Row() take a RowImpl* as the first param.
			return Row(raw, &res, fetch_lengths(impl),
					res.throw_exceptions());
		}
		else {
			return Row();
		}
	}
................................................................................
	{
		return mysql_num_fields(MYSQL_RES_FROM_IMPL(impl));
	}

	/// \brief Returns the number of rows in the given result set
	///
	/// Wraps \c mysql_num_rows() in MySQL C API.



	ulonglong num_rows(ResultBase::Impl& impl) const
	{
		// FIXME: Do we still need this?  It might have been used only
		// as part of the "store" query implementation.  Recommend
		// calling res.length() instead?
		return mysql_num_rows(MYSQL_RES_FROM_IMPL(impl));
	}

	/// \brief "Pings" the MySQL database
	///
	/// This function will try to reconnect to the server if the 
	/// connection has been dropped.  Wraps \c mysql_ping() in the MySQL C API.







<
<
<
<
<
<







 







<
<







 







>
>
>


<
<
<







88
89
90
91
92
93
94






95
96
97
98
99
100
101
...
197
198
199
200
201
202
203


204
205
206
207
208
209
210
...
312
313
314
315
316
317
318
319
320
321
322
323



324
325
326
327
328
329
330
		rows_(rows)
		{
		}

		~ResultImpl() { /* implicit mysql_free_result(res_.raw()) */  }
		operator MYSQL_RES*() const { return res_.raw(); }







		size_t rows() const { return rows_; }

	private:
		// Has to be mutable because so many Connector/C APIs take
		// non-const MYSQL_RES*, and we call those from const methods.
		mutable RefCountedPointer<MYSQL_RES> res_;

................................................................................

	/// \brief Returns the next DB row from the given result set.
	///
	/// Wraps \c mysql_fetch_row() in MySQL C API.
	Row fetch_row(ResultBase& res, ResultBase::Impl& impl)
	{
		if (MYSQL_ROW raw = mysql_fetch_row(MYSQL_RES_FROM_IMPL(impl))) {


			return Row(raw, &res, fetch_lengths(impl),
					res.throw_exceptions());
		}
		else {
			return Row();
		}
	}
................................................................................
	{
		return mysql_num_fields(MYSQL_RES_FROM_IMPL(impl));
	}

	/// \brief Returns the number of rows in the given result set
	///
	/// Wraps \c mysql_num_rows() in MySQL C API.
	///
	/// \internal This is needed by Query::store(), so it can reserve
	/// storage space for the number of known rows in the result set.
	ulonglong num_rows(ResultBase::Impl& impl) const
	{



		return mysql_num_rows(MYSQL_RES_FROM_IMPL(impl));
	}

	/// \brief "Pings" the MySQL database
	///
	/// This function will try to reconnect to the server if the 
	/// connection has been dropped.  Wraps \c mysql_ping() in the MySQL C API.

Added src/mysql/ft.cpp.









































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/***********************************************************************
 mysql/ft.cpp - Implements the MySQLFieldType class, as well as some
 	internal helper classes.

 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2007, 2014-2015 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "common.h"
#include "ft.h"

#include "datetime.h"
#include "myset.h"
#include "sql_types.h"

#if defined(LIBTABULA_MYSQL_HEADERS_BURIED)
#	include <mysql/mysql.h>
#else
#	include <mysql.h>
#endif

#include <string>

using namespace std;

namespace libtabula {

MySQLFieldType::Base MySQLFieldType::base_type(enum_field_types t)
{
	switch (t) {
		case MYSQL_TYPE_TINY:
		case MYSQL_TYPE_SHORT:
		case MYSQL_TYPE_INT24:
		case MYSQL_TYPE_LONG:
		case MYSQL_TYPE_LONGLONG:
			return ft_integer;

		case MYSQL_TYPE_DECIMAL:
		case MYSQL_TYPE_NEWDECIMAL:
		case MYSQL_TYPE_FLOAT:
		case MYSQL_TYPE_DOUBLE:
			return ft_real;

		case MYSQL_TYPE_DATE:
#if MYSQL_VERSION_ID >= 50000
		case MYSQL_TYPE_NEWDATE:
#endif
		case MYSQL_TYPE_YEAR:
			return ft_date;

		case MYSQL_TYPE_TIME:
			return ft_time;

		case MYSQL_TYPE_DATETIME:
		case MYSQL_TYPE_TIMESTAMP:
			return ft_datetime;

		case MYSQL_TYPE_ENUM:
			return ft_enum;

		case MYSQL_TYPE_SET:
			return ft_set;

		case MYSQL_TYPE_BLOB:
		case MYSQL_TYPE_TINY_BLOB:
		case MYSQL_TYPE_MEDIUM_BLOB:
		case MYSQL_TYPE_LONG_BLOB:
			return ft_blob;

		case MYSQL_TYPE_VARCHAR:
		case MYSQL_TYPE_VAR_STRING:
		case MYSQL_TYPE_STRING:
			return ft_text;

		// MySQL 5.6+ compatibility types, never sent from the server to
		// us, but we have to handle them to avoid a compiler warning.
#if MYSQL_VERSION_ID >= 50600
		case MYSQL_TYPE_TIME2:
		case MYSQL_TYPE_DATETIME2:
		case MYSQL_TYPE_TIMESTAMP2:
			return ft_unsupported;
#endif

		// TODO: Add C++ data types to the library to allow us to
		// represent these SQL data types.
		case MYSQL_TYPE_BIT:
		case MYSQL_TYPE_GEOMETRY:
		case MYSQL_TYPE_NULL:		// BS!
			return ft_unsupported;

		// No default!  We want the compiler to warn us if the C API
		// adds another data type.
	}
}

} // end namespace libtabula

Added src/mysql/ft.h.



































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/// \file mysql/ft.h
/// \brief Implements the abstract FieldType interface for MySQL.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2008, 2014-2015 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#if !defined(LIBTABULA_TYPE_INFO_H)
#define LIBTABULA_TYPE_INFO_H

#include "common.h"

#include "field_type.h"

namespace libtabula {

/// \brief MySQL-specific field type information
///
/// \internal Used within libtabula for mapping SQL types to C++ types
/// and vice versa.
class LIBTABULA_EXPORT MySQLFieldType : public FieldType
{
public:
	/// \brief Standard constructor
	///
	/// \see FieldType::FieldType(Base, Flags)
	MySQLFieldType(Base b = ft_unsupported, Flag f = tf_default) :
	FieldType(b, f)
	{
	}

	/// \brief Create object from MySQL C API type info
	///
	/// \param t the underlying MySQL C API type ID for this type,
	/// typically given as MYSQL_FIELD::type
	/// \param flags is the MYSQL_FIELD::flags value
	MySQLFieldType(enum_field_types t, unsigned int flags) :
	FieldType(base_type(t),
			FieldType::tf_default | 
			(flags & UNSIGNED_FLAG ? FieldType::tf_unsigned : 0) |
			(flags & NOT_NULL_FLAG ? 0 : FieldType::tf_null))
	{
	}

	/// \brief Create object as a copy of another
	MySQLFieldType(const MySQLFieldType& other) : FieldType(other) { } 

private:
	/// \brief Return the FieldType::Base value corresponding to a given
	/// MySQL C API data type enum value.
	///
	/// \internal An implementation detail of the enum_field_types ctor.
	///
	/// \param t Underlying MySQL C API type constant
	static Base base_type(enum_field_types t);
};

} // end namespace libtabula

#endif // !defined(LIBTABULA_TYPE_INFO_H)

Changes to src/mystring.cpp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
29
30
31
32
33
34
35




36
37
38
39
40
41
42
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/***********************************************************************
 mystring.cpp - Implements the String class.

 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2008 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS.txt file
 in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................

#include <algorithm>
#include <stdexcept>
#include <string>

namespace libtabula {






char
String::at(size_type pos) const
{
	if (pos >= size()) {
		throw BadIndex("String", int(pos), int(size()));
	}
................................................................................
void
String::it_is_null()
{
	if (buffer_) {
		buffer_->set_null();
	}
	else {
		buffer_ = new SQLBuffer(0, 0, mysql_type_info::string_type, true);
	}
}


String::size_type
String::length() const
{




|
|
|







 







>
>
>
>







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/***********************************************************************
 mystring.cpp - Implements the String class.

 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2008, 2014 by Educational Technology Resources, Inc.  Others
 may also hold copyrights on code in this file.  See the CREDITS.txt
 file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................

#include <algorithm>
#include <stdexcept>
#include <string>

namespace libtabula {

// DB field type used for String objects when no other type info is
// given.  Just make it a generic "text string" type.
FieldType String::default_type_(FieldType::ft_text,
		FieldType::tf_default);

char
String::at(size_type pos) const
{
	if (pos >= size()) {
		throw BadIndex("String", int(pos), int(size()));
	}
................................................................................
void
String::it_is_null()
{
	if (buffer_) {
		buffer_->set_null();
	}
	else {
		buffer_ = new SQLBuffer(0, 0, default_type_, true);
	}
}


String::size_type
String::length() const
{

Changes to src/mystring.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231


















232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
...
645
646
647
648
649
650
651

652
653
654
655
656
657
658
659
/// \file mystring.h
/// \brief Declares String class, libtabula's generic std::string-like
/// class, used for holding data received from the database server.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2008 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS.txt file
 in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................
	String(const String& other) :
	buffer_(other.buffer_)
	{
	}

	/// \brief Full constructor.
	///
	/// \param str the string this object represents, or 0 for SQL null
	/// \param len the length of the string; embedded nulls are legal
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	/// The buffer will actually be 1 byte longer than the value given
	/// for \c len, to hold a null terminator for safety.  We do this
	/// because this ctor may be used for things other than
	/// null-terminated C strings.  (e.g. BLOB data)
	explicit String(const char* str, size_type len,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false) :
	buffer_(new SQLBuffer(str, len, type, is_null))
	{
	}

	/// \brief C++ string version of full ctor
	///
	/// \param str the string this object represents, or 0 for SQL null
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	explicit String(const std::string& str,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false) :
	buffer_(new SQLBuffer(str.data(), static_cast<size_type>(str.length()),
			type, is_null))
	{
	}

	/// \brief Null-terminated C string version of full ctor
	///
	/// \param str the string this object represents, or 0 for SQL null
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	explicit String(const char* str,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false) :
	buffer_(new SQLBuffer(str, static_cast<size_type>(strlen(str)),
			type, is_null))
	{
	}



















	/// \brief Destroy string
	~String() { }

	/// \brief Assign raw data to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const char* str, size_type len,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str, len, type, is_null);
	}

	/// \brief Assign a C++ string to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const std::string& str,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str.data(),
				static_cast<size_type>(str.length()), type, is_null);
	}

	/// \brief Assign a C string to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const char* str,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str, static_cast<size_type>(strlen(str)),
				type, is_null);
	}

	/// \brief Return a character within the string.
................................................................................
	/// If you know the data doesn't contain null characters (i.e. it's
	/// a typical string, not BLOB data), it's more efficient to just
	/// assign this object to anything taking \c const \c char*.  (Or
	/// equivalently, call the \c data() method.)  This copies a pointer
	/// to a buffer instead of copying the buffer's contents.
	void to_string(std::string& s) const;

	/// \brief Get this object's current MySQL type.
	mysql_type_info type() const
	{
		return buffer_ ? buffer_->type() : mysql_type_info::string_type;
	}

	/// \brief Assignment operator, from C++ string
	String& operator =(const std::string& rhs)
	{
		buffer_ = new SQLBuffer(rhs.data(),
				static_cast<size_type>(rhs.length()),
				mysql_type_info::string_type, false);

		return *this;
	}

	/// \brief Assignment operator, from C string
	///
	/// This creates a copy of the entire string, not just a copy of
	/// the pointer.
	String& operator =(const char* str)
	{
		buffer_ = new SQLBuffer(str,
				static_cast<size_type>(strlen(str)),
				mysql_type_info::string_type, false);

		return *this;
	}

	/// \brief Assignment operator, from other String
	///
	/// This only copies the pointer to the other String's data
................................................................................
			throw BadConversion(type_name, data(), 0, length());
		}
		else {
			return 0;
		}
	}


	RefCountedBuffer buffer_;	///< reference-counted data buffer

	friend class SQLTypeAdapter;
};

LIBTABULA_EXPORT std::ostream& operator <<(std::ostream& o,
		const String& in);






|
|
|
|







 







|










|







|





|








|





|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











|












|













|







 







|
|

|







|












|







 







>
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
/// \file mystring.h
/// \brief Declares String class, libtabula's generic std::string-like
/// class, used for holding data received from the database server.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB,
 and © 2004-2008, 2015 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
................................................................................
	String(const String& other) :
	buffer_(other.buffer_)
	{
	}

	/// \brief Full constructor.
	///
	/// \param str the string this object represents
	/// \param len the length of the string; embedded nulls are legal
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	/// The buffer will actually be 1 byte longer than the value given
	/// for \c len, to hold a null terminator for safety.  We do this
	/// because this ctor may be used for things other than
	/// null-terminated C strings.  (e.g. BLOB data)
	explicit String(const char* str, size_type len,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false) :
	buffer_(new SQLBuffer(str, len, type, is_null))
	{
	}

	/// \brief C++ string version of full ctor
	///
	/// \param str the string this object represents
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	explicit String(const std::string& str,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false) :
	buffer_(new SQLBuffer(str.data(), static_cast<size_type>(str.length()),
			type, is_null))
	{
	}

	/// \brief Null-terminated C string version of full ctor
	///
	/// \param str the string this object represents
	/// \param type MySQL type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	explicit String(const char* str,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false) :
	buffer_(new SQLBuffer(str, static_cast<size_type>(strlen(str)),
			type, is_null))
	{
	}

	/// \brief String-to-T conversion ctor
	///
	/// This constructor is mainly used by SSQLS, since it knows the
	/// expected C++ data type of a given SQL value, so it is calling
	/// this ctor to save both the raw SQL string data and that type.
	///
	/// \param str the string this object represents
	/// \param type C++ type information for data within str
	/// \param is_null string represents a SQL null, not literal data
	///
	/// The resulting object will contain a copy of the string buffer.
	explicit String(const std::string& str, const std::type_info& type,
			bool is_null = false) :
	buffer_(new SQLBuffer(str.data(), static_cast<size_type>(str.length()),
			type, is_null))
	{
	}

	/// \brief Destroy string
	~String() { }

	/// \brief Assign raw data to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const char* str, size_type len,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str, len, type, is_null);
	}

	/// \brief Assign a C++ string to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const std::string& str,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str.data(),
				static_cast<size_type>(str.length()), type, is_null);
	}

	/// \brief Assign a C string to this object
	///
	/// This parallels the ctor with the same parameters, for when you
	/// must do a 2-step create, or when you want to reassign the data 
	/// without creating a String temporary to get around the fact
	/// that operator=() can only take one parameter.
	void assign(const char* str,
			FieldType::Base type = FieldType::ft_text,
			bool is_null = false)
	{
		buffer_ = new SQLBuffer(str, static_cast<size_type>(strlen(str)),
				type, is_null);
	}

	/// \brief Return a character within the string.
................................................................................
	/// If you know the data doesn't contain null characters (i.e. it's
	/// a typical string, not BLOB data), it's more efficient to just
	/// assign this object to anything taking \c const \c char*.  (Or
	/// equivalently, call the \c data() method.)  This copies a pointer
	/// to a buffer instead of copying the buffer's contents.
	void to_string(std::string& s) const;

	/// \brief Get this object's current field type.
	FieldType type() const
	{
		return buffer_ ? buffer_->type() : default_type_;
	}

	/// \brief Assignment operator, from C++ string
	String& operator =(const std::string& rhs)
	{
		buffer_ = new SQLBuffer(rhs.data(),
				static_cast<size_type>(rhs.length()),
				FieldType::ft_text, false);

		return *this;
	}

	/// \brief Assignment operator, from C string
	///
	/// This creates a copy of the entire string, not just a copy of
	/// the pointer.
	String& operator =(const char* str)
	{
		buffer_ = new SQLBuffer(str,
				static_cast<size_type>(strlen(str)),
				FieldType::ft_text, false);

		return *this;
	}

	/// \brief Assignment operator, from other String
	///
	/// This only copies the pointer to the other String's data
................................................................................
			throw BadConversion(type_name, data(), 0, length());
		}
		else {
			return 0;
		}
	}

	static FieldType default_type_; ///< default string type
	RefCountedBuffer buffer_;		///< reference-counted data buffer

	friend class SQLTypeAdapter;
};

LIBTABULA_EXPORT std::ostream& operator <<(std::ostream& o,
		const String& in);

Changes to src/row.cpp.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
			size_type size = res->num_fields();
			data_.reserve(size);
			for (size_type i = 0; i < size; ++i) {
				bool is_null = row[i] == 0;
				data_.push_back(value_type(
						is_null ? "NULL" : row[i],
						is_null ? 4 : lengths[i],
						res->field_type(int(i)),
						is_null));
			}

			field_names_ = res->field_names();
			initialized_ = true;
		}
		else if (throw_exceptions) {







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
			size_type size = res->num_fields();
			data_.reserve(size);
			for (size_type i = 0; i < size; ++i) {
				bool is_null = row[i] == 0;
				data_.push_back(value_type(
						is_null ? "NULL" : row[i],
						is_null ? 4 : lengths[i],
						res->field_type(int(i)).base_type(),
						is_null));
			}

			field_names_ = res->field_names();
			initialized_ = true;
		}
		else if (throw_exceptions) {

Changes to src/sql_buffer.cpp.

1
2
3
4
5
6
7
8
9
10
11
12
..
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62







63
64
65
66
67
68
69
/***********************************************************************
 sql_buffer.cpp - Implements the SQLBuffer class.

 Copyright © 2007-2008 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
................................................................................
#include "datetime.h"
#include "sql_types.h"

#include <string.h>

namespace libtabula {



SQLBuffer&
SQLBuffer::assign(const char* data, size_type length, mysql_type_info type,
		bool is_null)
{
	replace_buffer(data, length);
	type_ = type;
	is_null_ = is_null;
	return *this;
}

SQLBuffer&
SQLBuffer::assign(const std::string& s, mysql_type_info type, bool is_null)
{
	replace_buffer(s.data(), s.length());
	type_ = type;
	is_null_ = is_null;
	return *this;
}

bool
SQLBuffer::quote_q() const
{
	if ((type_.base_type().c_type() == typeid(libtabula::sql_datetime)) &&
			data_ && (length_ >= 5) && (memcmp(data_, "NOW()", 5) == 0)) {
		// The default DATETIME value is special-cased as a call to the
		// SQL NOW() function, which must not be quoted.
		return false;







	}
	else {
		// Normal case: we can infer the need to quote from the type.
		return type_.quote_q();
	}
}




|
|







 







>


|









|










|




>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
..
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/***********************************************************************
 sql_buffer.cpp - Implements the SQLBuffer class.

 Copyright © 2007-2008, 2014 by Educational Technology Resources,
 Inc.  Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
................................................................................
#include "datetime.h"
#include "sql_types.h"

#include <string.h>

namespace libtabula {

FieldType SQLBuffer::string_type(FieldType::ft_text, FieldType::tf_null);

SQLBuffer&
SQLBuffer::assign(const char* data, size_type length, FieldType type,
		bool is_null)
{
	replace_buffer(data, length);
	type_ = type;
	is_null_ = is_null;
	return *this;
}

SQLBuffer&
SQLBuffer::assign(const std::string& s, FieldType type, bool is_null)
{
	replace_buffer(s.data(), s.length());
	type_ = type;
	is_null_ = is_null;
	return *this;
}

bool
SQLBuffer::quote_q() const
{
	if ((type_.c_type() == typeid(libtabula::sql_datetime)) &&
			data_ && (length_ >= 5) && (memcmp(data_, "NOW()", 5) == 0)) {
		// The default DATETIME value is special-cased as a call to the
		// SQL NOW() function, which must not be quoted.
		return false;
	}
	else if (is_null_) {
		// The value is null, which is a separate thing from the type
		// being null-able, so we have to check for it up here.  If
		// you try to push this check down into FieldType::is_null(),
		// something like "sql_int_null x = 5" would be quoted.
		return false;
	}
	else {
		// Normal case: we can infer the need to quote from the type.
		return type_.quote_q();
	}
}

Changes to src/sql_buffer.h.

24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#if !defined(LIBTABULA_SQL_BUFFER_H)
#define LIBTABULA_SQL_BUFFER_H


#include "refcounted.h"
#include "type_info.h"

#include <string>

namespace libtabula {

/// \brief Holds SQL data in string form plus type information for use
/// in converting the string to compatible C++ data types.

class SQLBuffer
{
public:
	/// \brief Type of length values
	typedef size_t size_type;








	/// \brief Initialize object as a copy of a raw data buffer
	///
	/// Copies the string into a new buffer one byte longer than
	/// the length value given, using that to hold a C string null
	/// terminator, just for safety.  The length value we keep does
	/// not include this extra byte, allowing this same mechanism
	/// to work for both C strings and binary data.
	SQLBuffer(const char* data, size_type length, mysql_type_info type,
			bool is_null) : data_(), length_(), type_(type),
			is_null_(is_null)
			{ replace_buffer(data, length); }

	/// \brief Initialize object as a copy of a C++ string object
	SQLBuffer(const std::string& s, mysql_type_info type, bool is_null) :
			data_(), length_(), type_(type), is_null_(is_null)
	{
		replace_buffer(s.data(), static_cast<size_type>(s.length()));
	}

	/// \brief Destructor
	~SQLBuffer() { delete[] data_; }

	/// \brief Replace contents of buffer with copy of given C string
	SQLBuffer& assign(const char* data, size_type length,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false);

	/// \brief Replace contents of buffer with copy of given C++ string
	SQLBuffer& assign(const std::string& s,
			mysql_type_info type = mysql_type_info::string_type,
			bool is_null = false);

	/// \brief Return pointer to raw data buffer
	const char* data() const { return data_; }

	/// \brief Returns true if we were initialized with a data type
	/// that must be escaped when used in a SQL query
	bool escape_q() const { return type_.escape_q(); }
................................................................................
	/// Count does not include the trailing null we tack on to our
	/// copy of the buffer for ease of use in C string contexts.
	/// We do this because we can be holding binary data just as
	/// easily as a C string.
	size_type length() const { return length_; }

	/// \brief Returns true if type of buffer's contents is string
	bool is_string() { return type_ == mysql_type_info::string_type; }

	/// \brief Return true if buffer's contents represent a SQL
	/// null.
	///
	/// The buffer's actual content will probably be "NULL" or
	/// something like it, but in the SQL data type system, a SQL
	/// null is distinct from a plain string with value "NULL".
................................................................................
	/// that must be quoted when used in a SQL query
	bool quote_q() const;

	/// \brief Sets the internal SQL null flag
	void set_null() { is_null_ = true; }

	/// \brief Return the SQL type of the data held in the buffer
	const mysql_type_info& type() const { return type_; }

private:
	SQLBuffer(const SQLBuffer&);
	SQLBuffer& operator=(const SQLBuffer&);

	/// \brief Common initialization for ctors
	void init(const char* pd, size_type len, mysql_type_info type,
			bool is_null);
	/// \brief Implementation detail of assign() and init()
	void replace_buffer(const char* pd, size_type length);

	const char* data_;		///< pointer to the raw data buffer
	size_type length_;		///< bytes in buffer, without trailing null
	mysql_type_info type_;	///< SQL type of data in the buffer
	bool is_null_;			///< if true, string represents a SQL null
};


/// \brief Reference-counted version of SQLBuffer.
///
/// No one uses SQLBuffer directly.  It exists only for use in a







>

<













>
>
>
>
>
>
>








|





|










<
|



<
|







 







|







 







|






|






|







24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79
80
81

82
83
84
85
86
87
88
89
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#if !defined(LIBTABULA_SQL_BUFFER_H)
#define LIBTABULA_SQL_BUFFER_H

#include "field_type.h"
#include "refcounted.h"


#include <string>

namespace libtabula {

/// \brief Holds SQL data in string form plus type information for use
/// in converting the string to compatible C++ data types.

class SQLBuffer
{
public:
	/// \brief Type of length values
	typedef size_t size_type;

	/// \brief Generic DBMS-independent "string" type definition
	///
	/// For consistency, the type is nullable, since SQLBuffer can
	/// always store a SQL null.  There is no non-nullable variant of
	/// SQLBuffer.  It either holds a null or it does not.
	static FieldType string_type;

	/// \brief Initialize object as a copy of a raw data buffer
	///
	/// Copies the string into a new buffer one byte longer than
	/// the length value given, using that to hold a C string null
	/// terminator, just for safety.  The length value we keep does
	/// not include this extra byte, allowing this same mechanism
	/// to work for both C strings and binary data.
	SQLBuffer(const char* data, size_type length, FieldType type,
			bool is_null) : data_(), length_(), type_(type),
			is_null_(is_null)
			{ replace_buffer(data, length); }

	/// \brief Initialize object as a copy of a C++ string object
	SQLBuffer(const std::string& s, FieldType type, bool is_null) :
			data_(), length_(), type_(type), is_null_(is_null)
	{
		replace_buffer(s.data(), static_cast<size_type>(s.length()));
	}

	/// \brief Destructor
	~SQLBuffer() { delete[] data_; }

	/// \brief Replace contents of buffer with copy of given C string
	SQLBuffer& assign(const char* data, size_type length,

			FieldType type = string_type, bool is_null = false);

	/// \brief Replace contents of buffer with copy of given C++ string
	SQLBuffer& assign(const std::string& s,

			FieldType type = string_type, bool is_null = false);

	/// \brief Return pointer to raw data buffer
	const char* data() const { return data_; }

	/// \brief Returns true if we were initialized with a data type
	/// that must be escaped when used in a SQL query
	bool escape_q() const { return type_.escape_q(); }
................................................................................
	/// Count does not include the trailing null we tack on to our
	/// copy of the buffer for ease of use in C string contexts.
	/// We do this because we can be holding binary data just as
	/// easily as a C string.
	size_type length() const { return length_; }

	/// \brief Returns true if type of buffer's contents is string
	bool is_string() { return type_ == string_type; }

	/// \brief Return true if buffer's contents represent a SQL
	/// null.
	///
	/// The buffer's actual content will probably be "NULL" or
	/// something like it, but in the SQL data type system, a SQL
	/// null is distinct from a plain string with value "NULL".
................................................................................
	/// that must be quoted when used in a SQL query
	bool quote_q() const;

	/// \brief Sets the internal SQL null flag
	void set_null() { is_null_ = true; }

	/// \brief Return the SQL type of the data held in the buffer
	const FieldType& type() const { return type_; }

private:
	SQLBuffer(const SQLBuffer&);
	SQLBuffer& operator=(const SQLBuffer&);

	/// \brief Common initialization for ctors
	void init(const char* pd, size_type len, FieldType type,
			bool is_null);
	/// \brief Implementation detail of assign() and init()
	void replace_buffer(const char* pd, size_type length);

	const char* data_;		///< pointer to the raw data buffer
	size_type length_;		///< bytes in buffer, without trailing null
	FieldType type_;		///< type of data in the buffer
	bool is_null_;			///< if true, string represents a SQL null
};


/// \brief Reference-counted version of SQLBuffer.
///
/// No one uses SQLBuffer directly.  It exists only for use in a

Changes to src/sql_types.h.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
	typedef int32_t					sql_int;
	typedef uint32_t				sql_int_unsigned;
	typedef int32_t					sql_mediumint;
	typedef uint32_t				sql_mediumint_unsigned;
	typedef int64_t					sql_bigint;
	typedef uint64_t				sql_bigint_unsigned;
#else
	// Assume a system where C99 is supported in C++ in advance of
	// actual standardization, so we can do this portably.
	typedef tiny_int<int8_t>		sql_tinyint;
	typedef tiny_int<uint8_t>		sql_tinyint_unsigned;
	typedef int16_t					sql_smallint;
	typedef uint16_t				sql_smallint_unsigned;
	typedef int32_t					sql_int;
	typedef uint32_t				sql_int_unsigned;
	typedef int32_t					sql_mediumint;
	typedef uint32_t				sql_mediumint_unsigned;
	typedef int64_t					sql_bigint;
	typedef uint64_t				sql_bigint_unsigned;
#endif

// Now define typedef equivalencies for the other standard MySQL
// data types.  There aren't serious portability issues here.
typedef float					sql_float;
typedef double					sql_double;
typedef double					sql_decimal;







|
<
|
|
|
|
|
|
|
|
|
|







101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
	typedef int32_t					sql_int;
	typedef uint32_t				sql_int_unsigned;
	typedef int32_t					sql_mediumint;
	typedef uint32_t				sql_mediumint_unsigned;
	typedef int64_t					sql_bigint;
	typedef uint64_t				sql_bigint_unsigned;
#else
	// Boo, we're going to have to wing it.

	typedef tiny_int<signed char>	sql_tinyint;
	typedef tiny_int<unsigned char>	sql_tinyint_unsigned;
	typedef signed short			sql_smallint;
	typedef unsigned short			sql_smallint_unsigned;
	typedef signed int				sql_int;
	typedef unsigned int			sql_int_unsigned;
	typedef signed int				sql_mediumint;
	typedef unsigned int			sql_mediumint_unsigned;
	typedef longlong				sql_bigint;
	typedef ulonglong				sql_bigint_unsigned;
#endif

// Now define typedef equivalencies for the other standard MySQL
// data types.  There aren't serious portability issues here.
typedef float					sql_float;
typedef double					sql_double;
typedef double					sql_decimal;

Changes to src/stadapter.cpp.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
SQLTypeAdapter::SQLTypeAdapter(const String& other, bool processed) :
buffer_(other.buffer_),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const std::string& str, bool processed) :
buffer_(new SQLBuffer(str, mysql_type_info::string_type, false)),
is_processed_(processed)
{
}

#if !defined(DOXYGEN_IGNORE)
SQLTypeAdapter::SQLTypeAdapter(const Null<string>& str, bool processed) :
buffer_(new SQLBuffer(str.is_null ? null_str : str.data,
		str.is_null ? typeid(void) : typeid(str.data), str.is_null)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const Null<String>& str, bool processed) :
buffer_(new SQLBuffer(
		str.is_null ? null_str.c_str() : str.data.data(),
		str.is_null ? null_str.length() : str.data.length(),
		str.is_null ? typeid(void) : typeid(str.data), str.is_null)),
is_processed_(processed)
{
}
#endif

SQLTypeAdapter::SQLTypeAdapter(const char* str, bool processed) :
buffer_(new SQLBuffer(str, strlen(str), mysql_type_info::string_type, false)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const char* str, int len, bool processed) :
buffer_(new SQLBuffer(str, len, mysql_type_info::string_type, false)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(char c) :
buffer_(new SQLBuffer(stream2string(c), mysql_type_info::string_type, false)),
is_processed_(false)
{
}

#if !defined(DOXYGEN_IGNORE)
SQLTypeAdapter::SQLTypeAdapter(Null<char> c) :
buffer_(new SQLBuffer(c.is_null ? null_str : stream2string(c),
................................................................................
SQLTypeAdapter&
SQLTypeAdapter::assign(const char* pc, int len)
{
	if (len < 0) {
		len = int(strlen(pc));
	}

	buffer_ = new SQLBuffer(pc, len, mysql_type_info::string_type, false);
	is_processed_ = false;
	return *this;
}

SQLTypeAdapter&
SQLTypeAdapter::assign(const null_type&)
{
................................................................................
SQLTypeAdapter::quote_q() const
{
	// If no buffer, it means we're an empty string, so we need to be 
	// quoted to be expressed properly in SQL.
	return buffer_ ? buffer_->quote_q() : true;
}

int
SQLTypeAdapter::type_id() const
{
	return buffer_ ? buffer_->type().id() : 0;
}

} // end namespace libtabula








|







|








|






|





|





|







 







|







 







<
<
<
<
<
<


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
511
512
513
514
515
516
517






518
519
SQLTypeAdapter::SQLTypeAdapter(const String& other, bool processed) :
buffer_(other.buffer_),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const std::string& str, bool processed) :
buffer_(new SQLBuffer(str, SQLBuffer::string_type, false)),
is_processed_(processed)
{
}

#if !defined(DOXYGEN_IGNORE)
SQLTypeAdapter::SQLTypeAdapter(const Null<string>& str, bool processed) :
buffer_(new SQLBuffer(str.is_null ? null_str : str.data,
		SQLBuffer::string_type, str.is_null)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const Null<String>& str, bool processed) :
buffer_(new SQLBuffer(
		str.is_null ? null_str.c_str() : str.data.data(),
		str.is_null ? null_str.length() : str.data.length(),
		SQLBuffer::string_type, str.is_null)),
is_processed_(processed)
{
}
#endif

SQLTypeAdapter::SQLTypeAdapter(const char* str, bool processed) :
buffer_(new SQLBuffer(str, strlen(str), SQLBuffer::string_type, false)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(const char* str, int len, bool processed) :
buffer_(new SQLBuffer(str, len, SQLBuffer::string_type, false)),
is_processed_(processed)
{
}

SQLTypeAdapter::SQLTypeAdapter(char c) :
buffer_(new SQLBuffer(stream2string(c), SQLBuffer::string_type, false)),
is_processed_(false)
{
}

#if !defined(DOXYGEN_IGNORE)
SQLTypeAdapter::SQLTypeAdapter(Null<char> c) :
buffer_(new SQLBuffer(c.is_null ? null_str : stream2string(c),
................................................................................
SQLTypeAdapter&
SQLTypeAdapter::assign(const char* pc, int len)
{
	if (len < 0) {
		len = int(strlen(pc));
	}

	buffer_ = new SQLBuffer(pc, len, SQLBuffer::string_type, false);
	is_processed_ = false;
	return *this;
}

SQLTypeAdapter&
SQLTypeAdapter::assign(const null_type&)
{
................................................................................
SQLTypeAdapter::quote_q() const
{
	// If no buffer, it means we're an empty string, so we need to be 
	// quoted to be expressed properly in SQL.
	return buffer_ ? buffer_->quote_q() : true;
}







} // end namespace libtabula

Changes to src/stadapter.h.

275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
	size_type length() const;
	size_type size() const { return length(); } ///< alias for length()

	/// \brief Returns true if we were initialized with a data type
	/// that must be quoted when used in a SQL query
	bool quote_q() const;

	/// \brief Returns the type ID of the buffer's data
	///
	/// Values from type_info.h.  At the moment, these are the same as
	/// the underlying MySQL C API type IDs, but it's not a good idea
	/// to count on this remaining the case.
	int type_id() const;

	/// \brief Turns on the internal 'is_processed_' flag.
	///
	/// This is an implementation detail of template queries, used to
	/// prevent repeated processing of values.
	void set_processed() { is_processed_ = true; }

#if !defined(DOXYGEN_IGNORE)







<
<
<
<
<
<
<







275
276
277
278
279
280
281







282
283
284
285
286
287
288
	size_type length() const;
	size_type size() const { return length(); } ///< alias for length()

	/// \brief Returns true if we were initialized with a data type
	/// that must be quoted when used in a SQL query
	bool quote_q() const;








	/// \brief Turns on the internal 'is_processed_' flag.
	///
	/// This is an implementation detail of template queries, used to
	/// prevent repeated processing of values.
	void set_processed() { is_processed_ = true; }

#if !defined(DOXYGEN_IGNORE)

Deleted src/type_info.cpp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/***********************************************************************
 type_info.cpp - Implements the mysql_type_info class.

 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2007 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS.txt file
 in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "common.h"
#include "type_info.h"

#include "datetime.h"
#include "myset.h"
#include "sql_types.h"

#if defined(LIBTABULA_MYSQL_HEADERS_BURIED)
#	include <mysql/mysql.h>
#else
#	include <mysql.h>
#endif

#include <string>

using namespace std;

namespace libtabula {

// This table maps C++ type information to SQL type information.  As you
// can see, it's intimately tied in with MySQL's type constants, thus the
// name.  Unlike in earlier versions of libtabula, this table is the only
// place with such a dependency.  Everything else abstracts MySQL's
// type system away by bouncing things through this table.
//
// The second half of the table parallels the first, to handle null-able
// versions of the types in the first half.  This is required because
// SQL's 'null' concept does not map neatly into the C++ type system, so
// null-able versions of these types have to have a different C++ type,
// implemented using the Null template.  See null.h for further details.
//
// Types with tf_default set are added to a lookup map in the
// mysql_type_info_lookup class in order to provide reverse lookup
// of C++ types to SQL types.  If you take the subset of all items
// marked as default, the typeid() of each item must be unique.
const mysql_type_info::sql_type_info mysql_type_info::types[] = {
	sql_type_info("DECIMAL NOT NULL", typeid(sql_decimal),
#if MYSQL_VERSION_ID >= 50001
			MYSQL_TYPE_NEWDECIMAL
#else
			MYSQL_TYPE_DECIMAL
#endif
			),
	sql_type_info("TINYINT NOT NULL", typeid(sql_tinyint),
			MYSQL_TYPE_TINY, mysql_ti_sql_type_info::tf_default),
	sql_type_info("TINYINT UNSIGNED NOT NULL", typeid(sql_tinyint_unsigned),
			MYSQL_TYPE_TINY, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("SMALLINT NOT NULL", typeid(sql_smallint),
			MYSQL_TYPE_SHORT, mysql_ti_sql_type_info::tf_default),
	sql_type_info("SMALLINT UNSIGNED NOT NULL", typeid(sql_smallint_unsigned),
			MYSQL_TYPE_SHORT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("INT NOT NULL", typeid(sql_int),
			MYSQL_TYPE_LONG, mysql_ti_sql_type_info::tf_default),
	sql_type_info("INT UNSIGNED NOT NULL", typeid(sql_int_unsigned),
			MYSQL_TYPE_LONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("FLOAT NOT NULL", typeid(sql_float),
			MYSQL_TYPE_FLOAT, mysql_ti_sql_type_info::tf_default),
	sql_type_info("FLOAT UNSIGNED NOT NULL", typeid(sql_float),
			MYSQL_TYPE_FLOAT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("DOUBLE NOT NULL", typeid(sql_double),
			MYSQL_TYPE_DOUBLE, mysql_ti_sql_type_info::tf_default),
	sql_type_info("DOUBLE UNSIGNED NOT NULL", typeid(sql_double),
			MYSQL_TYPE_DOUBLE, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("NULL NOT NULL", typeid(void),
			MYSQL_TYPE_NULL, mysql_ti_sql_type_info::tf_default),
	sql_type_info("TIMESTAMP NOT NULL", typeid(sql_timestamp),
			MYSQL_TYPE_TIMESTAMP),
	sql_type_info("BIGINT NOT NULL", typeid(sql_bigint),
			MYSQL_TYPE_LONGLONG, mysql_ti_sql_type_info::tf_default),
	sql_type_info("BIGINT UNSIGNED NOT NULL", typeid(sql_bigint_unsigned),
			MYSQL_TYPE_LONGLONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("MEDIUMINT NOT NULL", typeid(sql_mediumint),
			MYSQL_TYPE_INT24, mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("MEDIUMINT UNSIGNED NOT NULL", typeid(sql_mediumint_unsigned),
			MYSQL_TYPE_INT24, mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("DATE NOT NULL", typeid(sql_date),
			MYSQL_TYPE_DATE, mysql_ti_sql_type_info::tf_default),
	sql_type_info("TIME NOT NULL", typeid(sql_time),
			MYSQL_TYPE_TIME, mysql_ti_sql_type_info::tf_default),
	sql_type_info("DATETIME NOT NULL", typeid(sql_datetime),
			MYSQL_TYPE_DATETIME, mysql_ti_sql_type_info::tf_default),
	sql_type_info("ENUM NOT NULL", typeid(sql_enum),
			MYSQL_TYPE_ENUM, mysql_ti_sql_type_info::tf_default),
	sql_type_info("SET NOT NULL", typeid(sql_set),
			MYSQL_TYPE_SET, mysql_ti_sql_type_info::tf_default),
	sql_type_info("TINYBLOB NOT NULL", typeid(sql_tinyblob),
			MYSQL_TYPE_TINY_BLOB),
	sql_type_info("MEDIUMBLOB NOT NULL", typeid(sql_mediumblob),
			MYSQL_TYPE_MEDIUM_BLOB),
	sql_type_info("LONGBLOB NOT NULL", typeid(sql_longblob),
			MYSQL_TYPE_LONG_BLOB),
	sql_type_info("BLOB NOT NULL", typeid(sql_blob),
			MYSQL_TYPE_BLOB, mysql_ti_sql_type_info::tf_default),
	sql_type_info("VARCHAR NOT NULL", typeid(sql_varchar),
			MYSQL_TYPE_VAR_STRING, mysql_ti_sql_type_info::tf_default),
	sql_type_info("CHAR NOT NULL", typeid(sql_char),
			MYSQL_TYPE_STRING),

	sql_type_info("DECIMAL NULL", typeid(Null<sql_decimal>),
#if MYSQL_VERSION_ID >= 50001
			MYSQL_TYPE_NEWDECIMAL
#else
			MYSQL_TYPE_DECIMAL
#endif
			, mysql_ti_sql_type_info::tf_null),
	sql_type_info("TINYINT NULL", typeid(Null<sql_tinyint>),
			MYSQL_TYPE_TINY, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("TINYINT UNSIGNED NULL", typeid(Null<sql_tinyint_unsigned>),
			MYSQL_TYPE_TINY, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("SMALLINT NULL", typeid(Null<sql_smallint>),
			MYSQL_TYPE_SHORT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("SMALLINT UNSIGNED NULL", typeid(Null<sql_smallint_unsigned>),
			MYSQL_TYPE_SHORT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("INT NULL", typeid(Null<sql_int>),
			MYSQL_TYPE_LONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("INT UNSIGNED NULL", typeid(Null<sql_int_unsigned>),
			MYSQL_TYPE_LONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("FLOAT NULL", typeid(Null<sql_float>),
			MYSQL_TYPE_FLOAT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("FLOAT UNSIGNED NULL", typeid(Null<sql_float>),
			MYSQL_TYPE_FLOAT, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("DOUBLE NULL", typeid(Null<sql_double>),
			MYSQL_TYPE_DOUBLE, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("DOUBLE UNSIGNED NULL", typeid(Null<sql_double>),
			MYSQL_TYPE_DOUBLE, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("NULL NULL", typeid(Null<void>),
			MYSQL_TYPE_NULL, mysql_ti_sql_type_info::tf_null),
	sql_type_info("TIMESTAMP NULL", typeid(Null<sql_timestamp>),
			MYSQL_TYPE_TIMESTAMP),
	sql_type_info("BIGINT NULL", typeid(Null<sql_bigint>),
			MYSQL_TYPE_LONGLONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("BIGINT UNSIGNED NULL", typeid(Null<sql_bigint_unsigned>),
			MYSQL_TYPE_LONGLONG, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("MEDIUMINT NULL", typeid(Null<sql_mediumint>),
			MYSQL_TYPE_INT24, mysql_ti_sql_type_info::tf_null),
	sql_type_info("MEDIUMINT UNSIGNED NULL", typeid(Null<sql_mediumint_unsigned>), 
			MYSQL_TYPE_INT24, mysql_ti_sql_type_info::tf_null |
			mysql_ti_sql_type_info::tf_unsigned),
	sql_type_info("DATE NULL", typeid(Null<sql_date>),
			MYSQL_TYPE_DATE, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("TIME NULL", typeid(Null<sql_time>),
			MYSQL_TYPE_TIME, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("DATETIME NULL", typeid(Null<sql_datetime>),
			MYSQL_TYPE_DATETIME, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("ENUM NULL", typeid(Null<sql_enum>),
			MYSQL_TYPE_ENUM, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("SET NULL", typeid(Null<sql_set>),
			MYSQL_TYPE_SET, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("TINYBLOB NULL", typeid(Null<sql_tinyblob>),
			MYSQL_TYPE_TINY_BLOB, mysql_ti_sql_type_info::tf_null),
	sql_type_info("MEDIUMBLOB NULL", typeid(Null<sql_mediumblob>),
			MYSQL_TYPE_MEDIUM_BLOB, mysql_ti_sql_type_info::tf_null),
	sql_type_info("LONGBLOB NULL", typeid(Null<sql_longblob>),
			MYSQL_TYPE_LONG_BLOB, mysql_ti_sql_type_info::tf_null),
	sql_type_info("BLOB NULL", typeid(Null<sql_blob>),
			MYSQL_TYPE_BLOB, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("VARCHAR NULL", typeid(Null<sql_varchar>),
			MYSQL_TYPE_VAR_STRING, mysql_ti_sql_type_info::tf_default |
			mysql_ti_sql_type_info::tf_null),
	sql_type_info("CHAR NULL", typeid(Null<sql_char>),
			MYSQL_TYPE_STRING, mysql_ti_sql_type_info::tf_null)
};

const int mysql_type_info::num_types =
		sizeof(mysql_type_info::types) / sizeof(mysql_type_info::types[0]);

const mysql_type_info::sql_type_info_lookup
		mysql_type_info::lookups(mysql_type_info::types,
		mysql_type_info::num_types);

#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.

mysql_ti_sql_type_info_lookup::mysql_ti_sql_type_info_lookup(
		const sql_type_info types[], const int size)
{
	for (int i = 0; i < size; ++i) {
		if (types[i].is_default()) {
			map_[types[i].c_type_] = i;
		}
	}
}

#endif // !defined(DOXYGEN_IGNORE)

unsigned char mysql_type_info::type(enum_field_types t,
		bool _unsigned, bool _null)
{
	for (unsigned char i = 0; i < num_types; ++i) {
		if ((types[i].base_type_ == t) &&
				(!_unsigned || types[i].is_unsigned()) &&
				(!_null || types[i].is_null())) {
			return i;
		}
	}

	return type(MYSQL_TYPE_STRING, false, _null);	// punt!
}

bool mysql_type_info::quote_q() const
{
	const type_info& ti = base_type().c_type();
	return ti == typeid(string) ||
			ti == typeid(sql_date) ||
			ti == typeid(sql_time) ||
			ti == typeid(sql_datetime) ||
			ti == typeid(sql_blob) ||
			ti == typeid(sql_tinyblob) ||
			ti == typeid(sql_mediumblob) ||
			ti == typeid(sql_longblob) ||
			ti == typeid(sql_char) ||
			ti == typeid(sql_set);
}

bool mysql_type_info::escape_q() const
{
	const type_info& ti = base_type().c_type();
	return ti == typeid(string) ||
			ti == typeid(sql_enum) ||
			ti == typeid(sql_blob) ||
			ti == typeid(sql_tinyblob) ||
			ti == typeid(sql_mediumblob) ||
			ti == typeid(sql_longblob) ||
			ti == typeid(sql_char) ||
			ti == typeid(sql_varchar);
}

} // end namespace libtabula

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































Deleted src/type_info.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/// \file type_info.h
/// \brief Declares classes that provide an interface between the SQL
/// and C++ type systems.
///
/// These classes are mostly used internal to the library.

/***********************************************************************
 Copyright © 1998 by Kevin Atkinson, © 1999-2001 by MySQL AB, and
 © 2004-2008 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS.txt file
 in the top directory of the distribution for details.

 This file is part of libtabula.

 libtabula is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 libtabula is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with libtabula; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#if !defined(LIBTABULA_TYPE_INFO_H)
#define LIBTABULA_TYPE_INFO_H

#include "common.h"

#include "exceptions.h"

#include <map>
#include <sstream>
#include <typeinfo>

namespace libtabula {

#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.

class LIBTABULA_EXPORT mysql_type_info;
class LIBTABULA_EXPORT mysql_ti_sql_type_info_lookup;

class LIBTABULA_EXPORT mysql_ti_sql_type_info
{
private:
	// For use with flags_ bitset
	enum {
		tf_default = 1,
		tf_null = 2,
		tf_unsigned = 4
	};

	friend class mysql_type_info;
	friend class mysql_ti_sql_type_info_lookup;

	mysql_ti_sql_type_info& operator=(
			const mysql_ti_sql_type_info& b);
	
	// Not initting _base_type and _default because only mysql_type_info
	// can create them.  There *must* be only one copy of each.
	mysql_ti_sql_type_info() :
	sql_name_(0),
	c_type_(0),
	base_type_(
#if MYSQL_VERSION_ID > 40000
		MYSQL_TYPE_NULL
#else
		FIELD_TYPE_NULL
#endif
	),
	flags_(0)
	{
	}
	
	mysql_ti_sql_type_info(const char* s,
			const std::type_info& t, const enum_field_types bt,
			const unsigned int flags = 0) :
	sql_name_(s),
	c_type_(&t),
	base_type_(bt),
	flags_(flags)
	{
	}

	bool is_default() const { return flags_ & tf_default; }
	bool is_null() const { return flags_ & tf_null; }
	bool is_unsigned() const { return flags_ & tf_unsigned; }

	const char* sql_name_;
	const std::type_info* c_type_;
	const enum_field_types base_type_;
	const unsigned int flags_;
};


struct type_info_cmp
{
	bool operator() (const std::type_info* lhs,
			const std::type_info* rhs) const
	{
		return lhs->before(*rhs) != 0;
	}
};

class LIBTABULA_EXPORT mysql_ti_sql_type_info_lookup
{
private:
	friend class mysql_type_info;

	typedef mysql_ti_sql_type_info sql_type_info;
	typedef std::map<const std::type_info*, unsigned char, type_info_cmp>
			map_type;

	mysql_ti_sql_type_info_lookup(const sql_type_info types[],
			const int size);

	const unsigned char& operator [](
			const std::type_info& ti) const
	{
		map_type::const_iterator it = map_.find(&ti);
		if (it != map_.end()) {
			return it->second;
		}
		else {
			std::ostringstream outs;
			outs << "Failed to find MySQL C API type ID for " << ti.name();
			throw TypeLookupFailed(outs.str());
		}
	}

	map_type map_;
};

#endif // !defined(DOXYGEN_IGNORE)


/// \brief SQL field type information
///
/// \internal Used within libtabula for mapping SQL types to C++ types
/// and vice versa.
class LIBTABULA_EXPORT mysql_type_info
{
public:
	/// \brief Default constructor
	///
	/// This only exists because FieldTypes keeps a vector of these
	/// objects.  You are expected to copy real values into it before
	/// using it via the copy ctor or one of the assignment operators.
	/// If you don't, we have arranged a pretty spectacular crash for
	/// your program.  So there.
	mysql_type_info() :
	num_(static_cast<unsigned char>(-1))
	{
	}

	/// \brief Create object from MySQL C API type info
	///
	/// \param t the underlying C API type ID for this type
	/// \param _unsigned if true, this is the unsigned version of the type
	/// \param _null if true, this type can hold a SQL null
	mysql_type_info(enum_field_types t, bool _unsigned = false,
			bool _null = false) :
	num_(type(t, _unsigned, _null))
	{
	}

	/// \brief Create object as a copy of another
	mysql_type_info(const mysql_type_info& t) :
	num_(t.num_)
	{
	}

	/// \brief Create object from a C++ type_info object
	///
	/// This tries to map a C++ type to the closest MySQL data type.
	/// It is necessarily somewhat approximate.
	mysql_type_info(const std::type_info& t) :
	num_(lookups[t])
	{
	}

	/// \brief Assign another mysql_type_info object to this object
	mysql_type_info& operator =(const mysql_type_info& t)
	{
		num_ = t.num_;
		return *this;
	}

	/// \brief Assign a C++ type_info object to this object
	///
	/// This tries to map a C++ type to the closest MySQL data type.
	/// It is necessarily somewhat approximate.
	mysql_type_info& operator =(const std::type_info& t)
	{
		num_ = lookups[t];
		return *this;
	}

	/// \brief Returns an implementation-defined name of the C++ type.
	///
	/// Returns the name that would be returned by typeid().name() for
	/// the C++ type associated with the SQL type.
	const char* name() const { return deref().c_type_->name(); }

	/// \brief Returns the name of the SQL type.
	///
	/// Returns the SQL name for the type.
	const char* sql_name() const { return deref().sql_name_; }

	/// \brief Returns the type_info for the C++ type associated with
	/// the SQL type.
	///
	/// Returns the C++ type_info record corresponding to the SQL type.
	const std::type_info& c_type() const { return *deref().c_type_; }

	/// \brief Returns the type_info for the C++ type inside of the
	/// libtabula::Null type.
	///
	/// Returns the type_info for the C++ type inside the libtabula::Null
	/// type.  If the type is not Null then this is the same as c_type().
	const mysql_type_info base_type() const
	{
		return mysql_type_info(deref().base_type_);
	}

	/// \brief Returns the ID of the SQL type.
	///
	/// Returns the ID number MySQL uses for this type.  Note: Do not
	/// depend on the value of this ID as it may change between MySQL
	/// versions.
	int id() const
	{
		return num_;
	}
	
	/// \brief Returns true if the SQL type is of a type that needs to
	/// be quoted.
	///
	/// \return true if the type needs to be quoted for syntactically
	/// correct SQL.
	bool quote_q() const;

	/// \brief Returns true if the SQL type is of a type that needs to
	/// be escaped.
	///
	/// \return true if the type needs to be escaped for syntactically
	/// correct SQL.
	bool escape_q() const;

	/// \brief Provides a way to compare two types for sorting.
	///
	/// Returns true if the SQL ID of this type is lower than that of
	/// another.  Used by libtabula::type_info_cmp when comparing types.
	bool before(mysql_type_info& b)
	{
		return num_ < b.num_;
	}

	/// \brief The internal constant we use for our string type.
	///
	/// We expose this because other parts of libtabula need to know
	/// what the string constant is at the moment.
	static const enum_field_types string_type =
#if MYSQL_VERSION_ID > 40000
		MYSQL_TYPE_STRING;
#else
		FIELD_TYPE_STRING;
#endif

private:
	typedef mysql_ti_sql_type_info sql_type_info;
	typedef mysql_ti_sql_type_info_lookup sql_type_info_lookup;

	static const sql_type_info types[];
	static const int num_types;

	static const sql_type_info_lookup lookups;

	/// \brief Return an index into mysql_type_info::types array given
	/// MySQL type information.
	///
	/// This function is used in mapping from MySQL type information
	/// (a type enum, and flags indicating whether it is unsigned and
	/// whether it can be 'null') to the closest C++ types available
	/// within libtabula.  Notice that nulls have to be handled specially:
	/// the SQL null concept doesn't map directly onto the C++ type
	/// system.  See null.h for details.
	///
	/// \param t Underlying C API type constant
	/// \param _unsigned if true, indicates the unsigned variant of a
	/// MySQL type
	/// \param _null if true, indicates the variant of the MySQL type
	/// that can also hold an SQL 'null' instead of regular data.
	///
	/// While libtabula is tied to MySQL, \c t is just an abstraction
	/// of enum_field_types from mysql_com.h.
	static unsigned char type(enum_field_types t,
			bool _unsigned, bool _null = false);

	const sql_type_info& deref() const
	{
		return types[num_];
	}

	unsigned char num_;
};

/// \brief Returns true if two mysql_type_info objects are equal.
inline bool operator ==(const mysql_type_info& a, const mysql_type_info& b)
{
	return a.id() == b.id();
}

/// \brief Returns true if two mysql_type_info objects are not equal.
inline bool operator !=(const mysql_type_info& a, const mysql_type_info& b)
{
	return a.id() != b.id();
}

/// \brief Returns true if a given mysql_type_info object is equal
/// to a given C++ type_info object.
inline bool operator ==(const std::type_info& a, const mysql_type_info& b)
{
	return a == b.c_type();
}

/// \brief Returns true if a given mysql_type_info object is not equal
/// to a given C++ type_info object.
inline bool operator !=(const std::type_info& a, const mysql_type_info& b)
{
	return a != b.c_type();
}

/// \brief Returns true if a given mysql_type_info object is equal
/// to a given C++ type_info object.
inline bool operator ==(const mysql_type_info& a, const std::type_info& b)
{
	return a.c_type() == b;
}

/// \brief Returns true if a given mysql_type_info object is not equal
/// to a given C++ type_info object.
inline bool operator !=(const mysql_type_info& a, const std::type_info& b)
{
	return a.c_type() != b;
}

}								// end namespace libtabula

#endif // !defined(LIBTABULA_TYPE_INFO_H)

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































































Changes to test/string.cpp.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}


// Checks that String's null comparison methods work right
static bool
test_null()
{
	libtabula::String not_null("", libtabula::mysql_type_info::string_type, false);
	libtabula::String is_null("", libtabula::mysql_type_info::string_type, true);
	if (not_null.is_null() == true) {
		std::cerr << "not_null.is_null() == true!" << std::endl;
		return false;
	}
	else if (not_null == libtabula::null) {
		std::cerr << "not_null == libtabula:null!" << std::endl;
		return false;







|
|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}


// Checks that String's null comparison methods work right
static bool
test_null()
{
	libtabula::String not_null("", libtabula::FieldType::ft_text, false);
	libtabula::String is_null("", libtabula::FieldType::ft_text, true);
	if (not_null.is_null() == true) {
		std::cerr << "not_null.is_null() == true!" << std::endl;
		return false;
	}
	else if (not_null == libtabula::null) {
		std::cerr << "not_null == libtabula:null!" << std::endl;
		return false;