source: sources/src/dataBaseSqlConstructor.cc @ 1500:872b0b69e0d5

Revision 1500:872b0b69e0d5, 22.3 KB checked in by niam, 12 months ago (diff)

{issue #103} added implementation of sl- and dl- lists

Line 
1/***************************************************************************
2 *            dataBaseSqlConstructor.cc
3 *
4 *  Mon Jul 18 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <libdodo/dataBaseSqlConstructor.h>
33#include <libdodo/types.h>
34#include <libdodo/toolsMisc.h>
35#include <libdodo/toolsString.h>
36#include <libdodo/dataBaseConnector.h>
37
38using namespace dodo::data::base::sql;
39
40const dodo::string constructor::statements[] = {
41    "=",
42    "='",
43    "'",
44    ",",
45    " ( ",
46    " ) ",
47    "select ",
48    " from ",
49    "*",
50    ":",
51    "',",
52    "),",
53    "insert ",
54    " into ",
55    " values ",
56    ") select ",
57    "update ",
58    " set ",
59    "delete ",
60    " where ",
61    " limit ",
62    " offset ",
63    " order by ",
64    " inner join ",
65    " outer join ",
66    " left join ",
67    " right join ",
68    " on ",
69    "NULL",
70};
71
72//-------------------------------------------------------------------
73
74condition::condition() : _limit(-1),
75                         _offset(-1)
76{
77}
78
79//-------------------------------------------------------------------
80
81condition::condition(const dodo::string &table,
82                     const dodo::string &statement) : _limit(-1),
83                                                    _offset(-1),
84                                                    _table(table),
85                                                    _statement(statement)
86{
87}
88
89//-------------------------------------------------------------------
90
91condition::condition(const dodo::string &table,
92                     const dodoStringArray &fields,
93                     const dodo::string &statement) : _limit(-1),
94                                                    _offset(-1),
95                                                    _table(table),
96                                                    _statement(statement),
97                                                    _fields(fields)
98{
99}
100
101//-------------------------------------------------------------------
102
103const condition &
104condition::limit(long a_limit) const
105{
106    _limit = a_limit;
107
108    return *this;
109}
110
111//-------------------------------------------------------------------
112
113const condition &
114condition::offset(long a_offset) const
115{
116    _offset = a_offset;
117
118    return *this;
119}
120
121//-------------------------------------------------------------------
122
123const condition &
124condition::order(const dodo::string &field,
125                 short direction) const
126{
127    dodo::string dir[] = {
128        " ASC",
129        " DESC",
130    };
131
132    switch (direction) {
133        case ORDER_DIRECTION_ASC:
134        case ORDER_DIRECTION_DESC:
135            if (!_orderby.empty())
136                _orderby += ", ";
137            _orderby += field;
138            _orderby += dir[direction];
139    }
140
141    return *this;
142}
143
144//-------------------------------------------------------------------
145
146const condition &
147condition::join(const dodo::string &table,
148                const dodo::string &condition,
149                short type) const
150{
151    __join__ j;
152
153    j.type = type;
154    j.table = table;
155    j.condition = condition;
156
157    _join.push_back(j);
158
159    return *this;
160}
161
162//-------------------------------------------------------------------
163
164condition::~condition()
165{
166}
167
168//-------------------------------------------------------------------
169
170rows::rows()
171{
172}
173
174//-------------------------------------------------------------------
175
176rows::rows(const dodoArray<dodoStringArray> &values,
177           const dodoStringArray &fields) : fields(fields),
178                                           values(values)
179{
180}
181
182//-------------------------------------------------------------------
183
184rows::rows(const dodoStringArray &a_values,
185           const dodoStringArray &fields) : fields(fields)
186{
187    values.push_back(a_values);
188}
189
190//-------------------------------------------------------------------
191
192rows::rows(const dodoArray<dodoStringMap> &map)
193{
194    dodoArray<dodoStringMap>::const_iterator i = map.begin(), j = map.end();
195
196    if (i != j) {
197        dodoStringMap::const_iterator o = i->begin(), p = i->end();
198
199        if (o != p) {
200            for (;o!=p;++o)
201                fields.push_back(o->first);
202
203            dodoStringArray array;
204            array.reserve(i->size());
205
206            for (;i!=j;++i) {
207                o = i->begin();
208                p = i->end();
209
210                for (;o!=p;++o)
211                    array.push_back(o->second);
212                values.push_back(array);
213
214                array.clear();
215            }
216        }
217    }
218}
219
220//-------------------------------------------------------------------
221
222rows::rows(const dodoStringMap &map)
223{
224    dodoStringMap::const_iterator o = map.begin(), p = map.end();
225    if (o!=p) {
226        for (;o!=p;++o)
227            fields.push_back(o->first);
228
229        o = map.begin();
230
231        dodoStringArray array;
232        array.reserve(map.size());
233
234        for (;o!=p;++o)
235            array.push_back(o->second);
236        values.push_back(array);
237    }
238}
239
240//-------------------------------------------------------------------
241
242rows::~rows()
243{
244}
245
246//-------------------------------------------------------------------
247
248query::query()
249{
250}
251
252//-------------------------------------------------------------------
253
254query::query(const dodo::string &sql) : sql(sql)
255{
256}
257
258//-------------------------------------------------------------------
259
260query::~query()
261{
262}
263
264//-------------------------------------------------------------------
265
266#ifndef DATABASE_WO_XEXEC
267constructor::__collected_data__::__collected_data__(xexec *a_executor,
268                                                    short execObject) : xexec::__collected_data__(a_executor, execObject),
269                                                                        type(REQUEST_NONE),
270                                                                        query(NULL)
271{
272}
273#else
274constructor::__collected_data__::__collected_data__() : type(REQUEST_NONE),
275                                                        query(NULL)
276{
277}
278#endif
279
280//-------------------------------------------------------------------
281
282void
283constructor::__collected_data__::clear()
284{
285    query = NULL;
286    type = REQUEST_NONE;
287    condition._orderby.clear();
288    condition._limit = -1;
289    condition._offset = -1;
290    condition._table.clear();
291    condition._statement.clear();
292    condition._fields.clear();
293    condition._join.clear();
294    rows.fields.clear();
295    rows.values.clear();
296}
297
298//-------------------------------------------------------------------
299
300constructor::constructor()
301#ifndef DATABASE_WO_XEXEC
302    : collectedData(this, xexec::OBJECT_XEXEC)
303#endif
304{
305}
306
307//-------------------------------------------------------------------
308
309constructor::~constructor()
310{
311}
312
313//-------------------------------------------------------------------
314
315void
316constructor::select(const dodo::data::base::condition &condition)
317{
318    collectedData.condition = *dynamic_cast<const sql::condition *>(&condition);
319
320    collectedData.type = REQUEST_SELECT;
321}
322
323//-------------------------------------------------------------------
324
325void
326constructor::insert(const dodo::data::base::rows      &rows,
327                    const dodo::data::base::condition &condition)
328{
329    collectedData.condition = *dynamic_cast<const sql::condition *>(&condition);
330    collectedData.rows = *dynamic_cast<const sql::rows *>(&rows);
331
332    collectedData.type = REQUEST_INSERT;
333}
334
335//-------------------------------------------------------------------
336
337void
338constructor::update(const dodo::data::base::rows      &rows,
339                    const dodo::data::base::condition &condition)
340{
341    collectedData.condition = *dynamic_cast<const sql::condition *>(&condition);
342    collectedData.rows = *dynamic_cast<const sql::rows *>(&rows);
343
344    collectedData.type = REQUEST_UPDATE;
345}
346
347//-------------------------------------------------------------------
348
349void
350constructor::remove(const dodo::data::base::condition &condition)
351{
352    collectedData.condition = *dynamic_cast<const sql::condition *>(&condition);
353
354    collectedData.type = REQUEST_REMOVE;
355}
356
357//-------------------------------------------------------------------
358
359void
360constructor::setFieldType(const dodo::string &table,
361                          const dodo::string &field,
362                          short            type)
363{
364    fieldTypes[table][field] = type;
365}
366
367//-------------------------------------------------------------------
368
369dodo::string
370constructor::select()
371{
372    dodo::string request;
373
374    if (collectedData.condition._table.size() > 0) {
375        request = statements[STATEMENT_SELECT];
376        if (collectedData.condition._fields.size() == 0)
377            request += statements[STATEMENT_STAR];
378        else
379            request += tools::misc::join(collectedData.condition._fields, statements[STATEMENT_COMA]);
380        request += statements[STATEMENT_FROM];
381        request += collectedData.condition._table;
382    } else {
383        request = statements[STATEMENT_SELECT];
384        if (collectedData.condition._fields.size() == 0)
385            request += statements[STATEMENT_STAR];
386        else
387            request += tools::misc::join(collectedData.condition._fields, statements[STATEMENT_COMA]);
388    }
389
390    if (collectedData.condition._statement.size() > 0) {
391        request += statements[STATEMENT_WHERE];
392        request += collectedData.condition._statement;
393    }
394
395    if (collectedData.condition._orderby.size() > 0) {
396        request += statements[STATEMENT_ORDERBY];
397        request += collectedData.condition._orderby;
398    }
399
400    if (collectedData.condition._limit != -1) {
401        request += statements[STATEMENT_LIMIT];
402        request += tools::string::lToString(collectedData.condition._limit);
403
404        if (collectedData.condition._offset != -1) {
405            request += statements[STATEMENT_OFFSET];
406            request += tools::string::lToString(collectedData.condition._offset);
407        }
408    }
409
410    if (collectedData.condition._join.size() > 0) {
411        dodoArray<condition::__join__>::iterator i = collectedData.condition._join.begin(), j = collectedData.condition._join.end();
412        for (;i!=j;++i) {
413            switch (i->type) {
414                case condition::JOIN_LEFT:
415                    request += statements[STATEMENT_JOINLEFT];
416
417                    break;
418
419                case condition::JOIN_RIGHT:
420                    request += statements[STATEMENT_JOINRIGHT];
421
422                    break;
423
424                case condition::JOIN_INNER:
425                    request += statements[STATEMENT_JOININNER];
426
427                    break;
428
429                case condition::JOIN_OUTER:
430                    request += statements[STATEMENT_JOINOUTER];
431
432                    break;
433            }
434            request += i->table;
435            if (!i->condition.empty()) {
436                request += statements[STATEMENT_ON];
437                request += i->condition;
438            }
439        }
440    }
441
442    return request;
443}
444
445//-------------------------------------------------------------------
446
447dodo::string
448constructor::insert()
449{
450    dodo::string request = statements[STATEMENT_INSERT];
451
452    request += statements[STATEMENT_INTO];
453    request += collectedData.condition._table;
454    if (collectedData.rows.fields.size() != 0) {
455        request += statements[STATEMENT_LEFTBRACKET];
456        request += tools::misc::join(collectedData.rows.fields, statements[STATEMENT_COMA]);
457        request += statements[STATEMENT_RIGHTBRACKET];
458    }
459    request += statements[STATEMENT_VALUES];
460
461    dodoArray<dodoStringArray>::iterator k(collectedData.rows.values.begin()), l(collectedData.rows.values.end());
462    if (k != l) {
463        dodoMap<dodo::string, dodoMap<dodo::string, short, dodoMapICaseStringCompare>, dodoMapICaseStringCompare>::iterator types = fieldTypes.find(collectedData.condition._table);
464        if (types != fieldTypes.end()) {
465            dodoMap<dodo::string, short, dodoMapICaseStringCompare>::iterator type;
466            dodoMap<dodo::string, short, dodoMapICaseStringCompare>::iterator typesEnd = types->second.end();
467
468            dodoStringArray::iterator t;
469
470            --l;
471            for (; k != l; ++k) {
472                request += statements[STATEMENT_LEFTBRACKET];
473
474                t = collectedData.rows.fields.begin();
475
476                dodoStringArray::const_iterator i(k->begin()), j(k->end() - 1);
477                for (; i != j; ++i, ++t) {
478                    type = types->second.find(*t);
479                    if (type != typesEnd) {
480                        if (type->second == FIELD_TEXT || type->second == FIELD_BINARY)
481                            request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHECOMA];
482                        else
483                            request += *i + statements[STATEMENT_COMA];
484                    } else
485                        request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHECOMA];
486                }
487                type = types->second.find(*t);
488                if (type != typesEnd) {
489                    if (type->second == FIELD_TEXT || type->second == FIELD_BINARY)
490                        request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHE];
491                    else
492                        request += *i;
493                } else
494                    request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHE];
495
496                request += statements[STATEMENT_RIGHTBRACKETCOMA];
497            }
498            request += statements[STATEMENT_LEFTBRACKET];
499
500            t = collectedData.rows.fields.begin();
501
502            dodoStringArray::const_iterator i(k->begin()), j(k->end() - 1);
503            for (; i != j; ++i, ++t) {
504                type = types->second.find(*t);
505                if (type != typesEnd) {
506                    if (type->second == FIELD_TEXT || type->second == FIELD_BINARY)
507                        request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHECOMA];
508                    else
509                        request += *i + statements[STATEMENT_COMA];
510                } else
511                    request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHECOMA];
512            }
513            type = types->second.find(*t);
514            if (type != typesEnd) {
515                if (type->second == FIELD_TEXT || type->second == FIELD_BINARY)
516                    request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHE];
517                else
518                    request += *i;
519            } else
520                request += statements[STATEMENT_APOSTROPHE] + escapeFields(*i) + statements[STATEMENT_APOSTROPHE];
521
522            request += statements[STATEMENT_RIGHTBRACKET];
523        } else {
524            --l;
525            for (; k != l; ++k) {
526                request += statements[STATEMENT_LEFTBRACKET];
527                request += joinFields(*k, statements[STATEMENT_COMA], statements[STATEMENT_APOSTROPHE]);
528                request += statements[STATEMENT_RIGHTBRACKETCOMA];
529            }
530            request += statements[STATEMENT_LEFTBRACKET];
531            request += joinFields(*k, statements[STATEMENT_COMA], statements[STATEMENT_APOSTROPHE]);
532            request += statements[STATEMENT_RIGHTBRACKET];
533        }
534    }
535
536    return request;
537}
538
539//-------------------------------------------------------------------
540
541dodo::string
542constructor::update()
543{
544    dodo::string request = statements[STATEMENT_UPDATE];
545
546    request += collectedData.condition._table;
547    request += statements[STATEMENT_SET];
548
549    dodoArray<dodoStringArray>::iterator v = collectedData.rows.values.begin();
550    if (v != collectedData.rows.values.end()) {
551        dodoStringArray::const_iterator i(collectedData.rows.fields.begin()), j(v->begin());
552        if (i != j) {
553            unsigned int fn(collectedData.rows.fields.size()), fv(v->size());
554
555            unsigned int o(fn <= fv ? fn : fv);
556
557            dodoMap<dodo::string, dodoMap<dodo::string, short, dodoMapICaseStringCompare>, dodoMapICaseStringCompare>::iterator types = fieldTypes.find(collectedData.condition._table);
558            if (types != fieldTypes.end()) {
559                dodoMap<dodo::string, short, dodoMapICaseStringCompare>::iterator type;
560                dodoMap<dodo::string, short, dodoMapICaseStringCompare>::iterator typesEnd = types->second.end();
561
562                --o;
563                for (unsigned int k(0); k < o; ++i, ++k, ++j) {
564                    request += *i;
565
566                    type = types->second.find(*i);
567                    if (type != typesEnd) {
568                        if (type->second == FIELD_TEXT || type->second == FIELD_BINARY) {
569                            request += statements[STATEMENT_EQUALAPOSTROPHE];
570                            request += escapeFields(*j);
571                            request += statements[STATEMENT_APOSTROPHECOMA];
572                        } else {
573                            request += statements[STATEMENT_EQUAL];
574                            request += *j;
575                            request += statements[STATEMENT_COMA];
576                        }
577                    } else {
578                        request += statements[STATEMENT_EQUALAPOSTROPHE];
579                        request += escapeFields(*j);
580                        request += statements[STATEMENT_APOSTROPHECOMA];
581                    }
582                }
583                request += *i;
584
585                type = types->second.find(*i);
586                if (type != typesEnd) {
587                    if (type->second == FIELD_TEXT || type->second == FIELD_BINARY) {
588                        request += statements[STATEMENT_EQUALAPOSTROPHE];
589                        request += escapeFields(*j);
590                        request += statements[STATEMENT_APOSTROPHE];
591                    } else {
592                        request += statements[STATEMENT_EQUAL];
593                        request += *j;
594                    }
595                } else {
596                    request += statements[STATEMENT_EQUALAPOSTROPHE];
597                    request += escapeFields(*j);
598                    request += statements[STATEMENT_APOSTROPHE];
599                }
600            } else {
601                --o;
602                for (unsigned int k(0); k < o; ++i, ++k, ++j) {
603                    request += *i;
604                    request += statements[STATEMENT_EQUALAPOSTROPHE];
605                    request += escapeFields(*j);
606                    request += statements[STATEMENT_APOSTROPHECOMA];
607                }
608                request += *i;
609                request += statements[STATEMENT_EQUALAPOSTROPHE];
610                request += escapeFields(*j);
611                request += statements[STATEMENT_APOSTROPHE];
612            }
613        }
614    }
615
616    if (collectedData.condition._statement.size() > 0) {
617        request += statements[STATEMENT_WHERE];
618        request += collectedData.condition._statement;
619    }
620
621    if (collectedData.condition._orderby.size() > 0) {
622        request += statements[STATEMENT_ORDERBY];
623        request += collectedData.condition._orderby;
624    }
625
626    if (collectedData.condition._limit != -1) {
627        request += statements[STATEMENT_LIMIT];
628        request += tools::string::lToString(collectedData.condition._limit);
629    }
630
631    return request;
632}
633
634//-------------------------------------------------------------------
635
636dodo::string
637constructor::remove()
638{
639    dodo::string request = statements[STATEMENT_DELETE];
640
641    request += statements[STATEMENT_FROM];
642    request += collectedData.condition._table;
643
644    if (collectedData.condition._statement.size() > 0) {
645        request += statements[STATEMENT_WHERE];
646        request += collectedData.condition._statement;
647    }
648
649    if (collectedData.condition._orderby.size() > 0) {
650        request += statements[STATEMENT_ORDERBY];
651        request += collectedData.condition._orderby;
652    }
653
654    if (collectedData.condition._limit != -1) {
655        request += statements[STATEMENT_LIMIT];
656        request += tools::string::lToString(collectedData.condition._limit);
657    }
658
659    return request;
660}
661
662//-------------------------------------------------------------------
663
664dodo::string
665constructor::construct()
666{
667    switch (collectedData.type) {
668        case REQUEST_SELECT:
669            return select();
670
671        case REQUEST_INSERT:
672            return insert();
673
674        case REQUEST_UPDATE:
675            return update();
676
677        case REQUEST_REMOVE:
678            return remove();
679    }
680
681    return __dodostring__;
682}
683
684//-------------------------------------------------------------------
685
686dodo::string
687constructor::escapeFields(const dodo::string &data)
688{
689    unsigned long size = data.size();
690    dodo::string temp('\0', size+size/4);
691
692    temp.clear();
693
694    for (unsigned long i = 0; i < size; ++i) {
695        if (data[i] == '\\' || data == '\'')
696            temp += '\\';
697        temp += data[i];
698    }
699
700    return temp;
701}
702
703//-------------------------------------------------------------------
704
705dodo::string
706constructor::joinFields(const dodoStringArray &fields,
707                        const dodo::string      &separator,
708                        const dodo::string      &frame,
709                        int                   limit)
710{
711    int k(0);
712
713    dodo::string temp, fs(frame + separator);
714    dodoStringArray::const_iterator i(fields.begin()), j(fields.end());
715    if (i != j) {
716        --j;
717        for (; i != j; ++i) {
718            if (limit != -1) {
719                if (k > limit)
720                    return temp;
721                ++k;
722            }
723            temp += frame;
724            temp += escapeFields(*i);
725            temp += fs;
726        }
727        temp += frame;
728        temp += escapeFields(*i);
729        temp += frame;
730    }
731
732    return temp;
733}
734
735//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.