File: 00300-DataDeveloperManual.html

package info (click to toggle)
poco-doc 1.3.6-1
  • links: PTS
  • area: main
  • in suites: buster, jessie, jessie-kfreebsd, squeeze, stretch, wheezy
  • size: 10,076 kB
  • ctags: 9,611
  • sloc: makefile: 31
file content (454 lines) | stat: -rw-r--r-- 17,481 bytes parent folder | download | duplicates (2)
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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>POCO Data Connectors Developer Guide</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="author" content="Applied Informatics Software Engineering GmbH and Contributors"/>
<meta name="publisher" content="Applied Informatics Software Engineering GmbH and Contributors"/>
<meta name="copyright" content="Copyright (c) 2009, Applied Informatics Software Engineering GmbH and Contributors"/>
<meta name="language" content="en"/>
<meta name="date" content="2009-11-24"/>
<meta name="generator" content="PocoDoc"/>
<link rel="stylesheet" href="css/styles.css" type="text/css"/>
</head>
<body bgcolor="#ffffff" leftmargin="0" topmargin="0">
<div class="header">
<h1 class="category">POCO Data Library</h1>
<h1 class="title">POCO Data Connectors Developer Guide</h1>
</div>
<div class="body">
<h2>Contents</h2>
<div class="toc"><ul>
<li class="level1"><a href="#0">Overview</a></li>
<li class="level1"><a href="#1">AbstractBinder</a></li>
<li class="level2"><a href="#2">Complete Interface</a></li>
<li class="level1"><a href="#3">AbstractExtractor</a></li>
<li class="level2"><a href="#4">Complete Interface</a></li>
<li class="level1"><a href="#5">AbstractPreparation</a></li>
<li class="level2"><a href="#6">Complete Interface</a></li>
<li class="level1"><a href="#7">StatementImpl</a></li>
<li class="level1"><a href="#8">SessionImpl</a></li>
<li class="level1"><a href="#9">Connector</a></li>
</ul></div>
<div class="description">
<p></p><h2><a name="0">Overview</a></h2><p>
Developing one's own <i>Data Connector</i> implementation is rather straight-forward. Just implement the following interfaces: </p>
<ul>
<li><a href="Poco.Data.AbstractBinder.html" title="class Poco::Data::AbstractBinder">Poco::Data::AbstractBinder</a> </li>
<li><a href="Poco.Data.AbstractExtractor.html" title="class Poco::Data::AbstractExtractor">Poco::Data::AbstractExtractor</a> </li>
<li><a href="Poco.Data.StatementImpl.html" title="class Poco::Data::StatementImpl">Poco::Data::StatementImpl</a> </li>
<li><a href="Poco.Data.SessionImpl.html" title="class Poco::Data::SessionImpl">Poco::Data::SessionImpl</a> </li>
<li><a href="Poco.Data.Connector.html" title="class Poco::Data::Connector">Poco::Data::Connector</a> </li>
<li>optional: <a href="Poco.Data.AbstractPreparation.html" title="class Poco::Data::AbstractPreparation">Poco::Data::AbstractPreparation</a> </li>
</ul>
<p>It is recommended to implement the classes from top to down (ie. start with Binder and Extractor) and to use a  namespace that has <tt> <a href="Poco.Data.html" title="namespace Poco::Data">Poco::Data</a> </tt> as parent, e.g.<tt> <a href="Poco.Data.SQLite.html" title="namespace Poco::Data::SQLite">Poco::Data::SQLite</a> </tt>. </p>
<p></p><h2><a name="1">AbstractBinder</a></h2><p>
An <tt>AbstractBinder</tt> is a class that maps values to placeholders. It is also responsible to bind primitive C++ data types to database  data types. The constructor of the subclass should receive everything needed to bind variables to  placeholders by position. An example taken from the SQLite implementation would be: </p>
<p></p>
<pre>Binder::Binder(sqlite3_stmt* pStmt):
    _pStmt(pStmt)
{
}

void Binder::bind(std::size_t pos, const Poco::Int32&amp; val)
{
    int rc = sqlite3_bind_int(_pStmt, (int)pos, val);
    checkReturn(rc);
}

void Binder::bind(std::size_t pos, const Poco::Int16&amp; val)
{
    Poco::Int32 tmp = val;
    bind(pos, tmp);
}
</pre>
<p> SQLite only needs an <i>sqlite3_stmt</i> as internal state, Int32 is bound via <i>sqlite3_bind_int</i> and Int16 values are mapped to Int32 values. </p>
<p></p><h3><a name="2">Complete Interface</a></h3><p>
All methods are public. </p>
<p></p>
<pre>AbstractBinder();
    /// Creates the AbstractBinder.

virtual ~AbstractBinder();
    /// Destroys the AbstractBinder.

virtual void bind(std::size_t pos, const Poco::Int8 &amp;val) = 0;
    /// Binds an Int8.

virtual void bind(std::size_t pos, const Poco::UInt8 &amp;val) = 0;
    /// Binds an UInt8.

virtual void bind(std::size_t pos, const Poco::Int16 &amp;val) = 0;
    /// Binds an Int16.

virtual void bind(std::size_t pos, const Poco::UInt16 &amp;val) = 0;
    /// Binds an UInt16.

virtual void bind(std::size_t pos, const Poco::Int32 &amp;val) = 0;
    /// Binds an Int32.

virtual void bind(std::size_t pos, const Poco::UInt32 &amp;val) = 0;
    /// Binds an UInt32.

virtual void bind(std::size_t pos, const Poco::Int64 &amp;val) = 0;
    /// Binds an Int64.

virtual void bind(std::size_t pos, const Poco::UInt64 &amp;val) = 0;
    /// Binds an UInt64.

virtual void bind(std::size_t pos, const bool &amp;val) = 0;
    /// Binds a boolean.

virtual void bind(std::size_t pos, const float &amp;val) = 0;
    /// Binds a float.

virtual void bind(std::size_t pos, const double &amp;val) = 0;
    /// Binds a double.

virtual void bind(std::size_t pos, const char &amp;val) = 0;
    /// Binds a single character.

virtual void bind(std::size_t pos, const char* const &amp;pVal) = 0;
    /// Binds a const char ptr.

virtual void bind(std::size_t pos, const std::string&amp; val) = 0;
    /// Binds a string.

virtual void bind(std::size_t pos, const BLOB&amp; val) = 0;
    /// Binds a BLOB.

virtual void reset() = 0;
    /// Resets the internal state, called before a rebind
</pre>
<p> </p>
<p></p><h2><a name="3">AbstractExtractor</a></h2><p>
An <tt>AbstractExtractor</tt> takes a result row and extracts from a given position one single value. It performs the reverse operation to the <tt>AbstractBinder</tt>, ie. it maps database types to primitive C++ types. An <tt>AbstractExtractor</tt> also has to handle null values. If it detects a null value, it is not allowed to modify the incoming value but will simply return false. An example taken from the SQLite implementation: </p>
<p></p>
<pre>Extractor::Extractor(sqlite3_stmt* pStmt):
    _pStmt(pStmt)
{
}

bool Extractor::extract(std::size_t pos, Poco::Int32&amp; val)
{
    if (isNull(pos&lt;[
        return false;
    val = sqlite3_column_int(_pStmt, (int)pos);
    return true;
}

bool Extractor::extract(std::size_t pos, Poco::Int16&amp; val)
{
    if (isNull(pos&lt;[
        return false;
    val = sqlite3_column_int(_pStmt, (int)pos);
    return true;
}
</pre>
<p> </p>
<p></p><h3><a name="4">Complete Interface</a></h3><p>
All methods are public. </p>
<p></p>
<pre>AbstractExtractor();
    /// Creates the AbstractExtractor.

virtual ~AbstractExtractor();
    /// Destroys the AbstractExtractor.

virtual bool extract(std::size_t pos, Poco::Int8&amp; val) = 0;
    /// Extracts an Int8. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::UInt8&amp; val) = 0;
    /// Extracts an UInt8. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::Int16&amp; val) = 0;
    /// Extracts an Int16. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::UInt16&amp; val) = 0;
    /// Extracts an UInt16. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::Int32&amp; val) = 0;
    /// Extracts an Int32. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::UInt32&amp; val) = 0;
    /// Extracts an UInt32. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::Int64&amp; val) = 0;
    /// Extracts an Int64. Returns false if null was received.

virtual bool extract(std::size_t pos, Poco::UInt64&amp; val) = 0;
    /// Extracts an UInt64. Returns false if null was received.

virtual bool extract(std::size_t pos, bool&amp; val) = 0;
    /// Extracts a boolean. Returns false if null was received.

virtual bool extract(std::size_t pos, float&amp; val) = 0;
    /// Extracts a float. Returns false if null was received.

virtual bool extract(std::size_t pos, double&amp; val) = 0;
    /// Extracts a double. Returns false if null was received.

virtual bool extract(std::size_t pos, char&amp; val) = 0;
    /// Extracts a single character. Returns false if null was received.

virtual bool extract(std::size_t pos, std::string&amp; val) = 0;
    /// Extracts a string. Returns false if null was received.

virtual bool extract(std::size_t pos, BLOB&amp; val) = 0;
    /// Extracts a BLOB. Returns false if null was received.
</pre>
<p> </p>
<p></p><h2><a name="5">AbstractPreparation</a></h2><p>
<tt>AbstractPreparation</tt> is an optional interface responsible for preparing an extract. If you need it depends on the <tt>DataConnector</tt> you implement. For example, SQLite can do perfectly without it, ODBC instead requires it. SQLite doesn't need it because it works as follows: </p>
<ul>
<li>sendQuery </li>
<li>getNextResult </li>
<li>extract single row values from result set </li>
</ul>
<p>This works because SQLites <i>getNextResult</i> provides the data as string, i.e. it doesn't need any type information. </p>
<p>The ODBC implementation is different: </p>
<ul>
<li>register/prepare for each column an output location </li>
<li>getNextResult </li>
<li>extract for each row the value by copying the content of the previously registered output location </li>
</ul>
<p><tt>AbstractPreparation</tt> is responsible for the first step. A typical prepare implementation will look like that: </p>
<p></p>
<pre>void prepare(std::size_t pos, Poco::Int32 val)
{
   _myVec[pos] =  Poco::Any a(val);
   int* i = AnyCast&lt;int&gt;(&amp;_myVec[pos]);
   //register int* i for output, Db specific
} 
</pre>
<p> Extract now changes to: </p>
<p></p>
<pre>bool Extractor::extract(std::size_t pos, Poco::Int16&amp; val)
{
    if (isNull(pos))
        return false;
    val = AnyCast&lt;int&gt;(_myVec[pos]);
    return true;
}
</pre>
<p> </p>
<p></p><h3><a name="6">Complete Interface</a></h3><p>
</p>
<p></p>
<pre>AbstractPreparation();
    /// Creates the AbstractPreparation.

virtual ~AbstractPreparation();
    /// Destroys the AbstractPreparation.

virtual void prepare(std::size_t pos, Poco::Int8) = 0;
    /// Prepares an Int8.

virtual void prepare(std::size_t pos, Poco::UInt8) = 0;
    /// Prepares an UInt8.

virtual void prepare(std::size_t pos, Poco::Int16) = 0;
    /// Prepares an Int16.

virtual void prepare(std::size_t pos, Poco::UInt16) = 0;
    /// Prepares an UInt16.

virtual void prepare(std::size_t pos, Poco::Int32) = 0;
    /// Prepares an Int32.

virtual void prepare(std::size_t pos, Poco::UInt32) = 0;
    /// Prepares an UInt32.

virtual void prepare(std::size_t pos, Poco::Int64) = 0;
    /// Prepares an Int64.

virtual void prepare(std::size_t pos, Poco::UInt64) = 0;
    /// Prepares an UInt64.

virtual void prepare(std::size_t pos, bool) = 0;
    /// Prepares a boolean.

virtual void prepare(std::size_t pos, float) = 0;
    /// Prepares a float.

virtual void prepare(std::size_t pos, double) = 0;
    /// Prepares a double.

virtual void prepare(std::size_t pos, char) = 0;
    /// Prepares a single character.

virtual void prepare(std::size_t pos, const std::string&amp; ) = 0;
    /// Prepares a string.

virtual void prepare(std::size_t pos, const BLOB&amp;) = 0;
</pre>
<p> </p>
<p>Note that it is recommended to prepare a statement only once in the compileImpl of <tt>StatementImpl</tt>. The AbstractPrepare objects (which make use of <tt>AbstractPreparation</tt> can be created by iterating over the Extractor objects of the StatementImpl: </p>
<p></p>
<pre>Poco::Data::AbstractExtractingVec::iterator it = extractings().begin();
Poco::Data::AbstractExtractingVec::iterator itEnd = extractings().end();
std::size_t pos = 0; // sqlite starts with pos 0 for results! your DB maybe with 1
for (; it != itEnd; ++it)
{
     AbstractPrepare* pPrep = (*it)-&gt;createPrepareObject(pPreparation, pos);
    _prepareVec.push_back(pPrep);
    (*it)-&gt;extract(pos);
    pos += (*it)-&gt;numOfColumnsHandled();
}
</pre>
<p> </p><h2><a name="7">StatementImpl</a></h2><p>
A <tt>StatementImpl</tt> stores as member a Binder and an Extractor (optional a Preparation object) and is responsible for compiling, binding, fetching single rows from the database and invoking the <i>Extracting</i> objects. The interface it has to implement is given as: </p>
<p></p>
<pre>public:
    StatementImpl();
        /// Creates the StatementImpl.

    virtual ~StatementImpl();
        /// Destroys the StatementImpl.

protected:
    virtual bool hasNext() = 0;
        /// Returns true if a call to next() will return data. Note that the 
        /// implementation must support several consecutive calls to hasNext 
        /// without data getting lost, ie. hasNext(); hasNext(); next() must 
        /// be equal to hasNext(); next();

    virtual void next() = 0;
        /// Retrieves the next row from the resultset.
        /// Will throw, if the resultset is empty.
        /// Expects the statement to be compiled and bound

    virtual bool canBind() const = 0;
        /// Returns if another bind is possible.

    virtual void compileImpl() = 0;
        /// Compiles the statement, doesn't bind yet.
        /// From now on AbstractBinder and AbstractExtractor 
        /// will be used

    virtual void bindImpl() = 0;
        /// Binds parameters.

    virtual AbstractExtractor&amp; extractor() = 0;
        /// Returns the concrete extractor used by the statement.

    virtual AbstractBinder&amp; binder() = 0;
        /// Returns the concrete binder used by the statement.  
</pre>
<p> </p>
<p>The Extracting and Binding objects can be accessed via the calls to the super-class methods <i>extractings()</i> and <i>bindings()</i>. A high-level <i>bind</i> implementation will look like this: </p>
<p></p>
<pre>[...]
Poco::Data::AbstractBindingVec&amp; binds = bindings();
std::size_t pos = 1; // or 0 depending on your database
Poco::Data::AbstractBindingVec::iterator it = binds.begin();
Poco::Data::AbstractBindingVec::iterator itEnd = binds.end();
for (; it != itEnd &amp;&amp; (*it)-&gt;canBind(); ++it)
{
    (*it)-&gt;bind(pos);
    pos += (*it)-&gt;numOfColumnsHandled();
}
</pre>
<p> </p>
<p>A high-level <i>next</i> implementation: </p>
<p></p>
<pre>if (!hasNext())
    throw Poco::Data::DataException(&quot;No data received&quot;);
int nCol = countColumnsInResult...;
poco_assert (columnsHandled() == nCol); 
Poco::Data::AbstractExtractingVec::iterator it = extractings().begin();
Poco::Data::AbstractExtractingVec::iterator itEnd = extractings().end();
std::size_t pos = 0; // sqlite starts with pos 0 for results! your DB maybe with 1
for (; it != itEnd; ++it)
{
    (*it)-&gt;extract(pos);
    pos += (*it)-&gt;numOfColumnsHandled();
}
enableHasNext();
</pre>
<p> </p>
<p>A high-level <i>hasNext</i> implementation: </p>
<p></p>
<pre>if (enabledhasNext())
{
    checkIfItHasMoreData
    cacheResult
    disablehasNext()
}

return cachedResult;
</pre>
<p> </p>
<p>A high-level <i>compileImpl</i>: </p>
<p></p>
<pre>if (compiled)
    return;

std::string sqlStmt(toString());

f database expects placeholders in different format than &quot;:name&quot;, parse and replace them

compile statement;

create Binder;
create Extractor;
</pre>
<p> </p>
<p>A high-level <i>canBind</i>: </p>
<p></p>
<pre>bool ret = false;
if (!bindings().empty() &amp;&amp; validCompiledStatement)
    ret = (*bindings().begin())-&gt;canBind();

return ret;
</pre>
<p> </p>
<p></p><h2><a name="8">SessionImpl</a></h2><p>
The purpose of the <tt>SessionImpl</tt> is simply to open/close a connection to the database, to act as factory for <tt>StatementImpl</tt> objects, and to handle transactions. The connection is opened in the constructor, and closed in the destructor. </p>
<p></p>
<pre>Poco::Data::StatementImpl* createStatementImpl();
    /// Returns an SQLite StatementImpl

void begin();
    /// Starts a transaction

void commit();
    /// Commits and ends a transaction

void rollback();
    /// Aborts a transaction
</pre>
<p> </p>
<p></p><h2><a name="9">Connector</a></h2><p>
Finally, one needs to implement the <tt>Connector</tt>. Each <tt>Connector</tt> should have a public static const string member named <i>KEY</i> and must have a factory method to <i>create</i> <tt> <a href="Poco.AutoPtr.html" title="class Poco::AutoPtr">Poco::AutoPtr</a> </tt> objects of type <tt>SessionImpl</tt>. It should also have a static <i>addToFactory()</i> and a static <i>removeFromFactory()</i> method: </p>
<p></p>
<pre>class My_API Connector: public Poco::Data::Connector
    /// Connector instantiates SessionImpl objects.
{
public:
    static const std::string KEY;
        /// Keyword for creating sessions

    Connector();
        /// Creates the Connector.

    ~Connector();
    /// Destroys the Connector.

    Poco::AutoPtr &lt; Poco::Data::SessionImpl &gt; createSession(const std::string&amp; connectionString);
        /// Creates a SessionImpl object and initializes it with the given connectionString.

    static void registerConnector();
        /// Registers the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory

    static void unregisterConnector();
        /// Unregisters the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory
};
</pre>
<p> </p>
<p></p>
</div>
<p class="footer">POCO C++ Libraries 1.3.6-all<br />
Copyright &copy; 2009, <a href="http://pocoproject.org/" target="_blank">Applied Informatics Software Engineering GmbH and Contributors</a></p>
</body>
</html>