Line data Source code
1 : // Snap Websites Server -- manage sessions for users, forms, etc.
2 : // Copyright (c) 2012-2019 Made to Order Software Corp. All Rights Reserved
3 : //
4 : // This program is free software; you can redistribute it and/or modify
5 : // it under the terms of the GNU General Public License as published by
6 : // the Free Software Foundation; either version 2 of the License, or
7 : // (at your option) any later version.
8 :
9 : //
10 : // This program is distributed in the hope that it will be useful,
11 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : // GNU General Public License for more details.
14 : //
15 : // You should have received a copy of the GNU General Public License
16 : // along with this program; if not, write to the Free Software
17 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 : //
19 :
20 : // self
21 : //
22 : #include "snapwebsites/dbutils.h"
23 :
24 : // snapwebsites lib
25 : //
26 : #include "snapwebsites/snap_exception.h"
27 : #include "snapwebsites/qstring_stream.h"
28 : #include "snapwebsites/log.h"
29 : #include "snapwebsites/mkgmtime.h"
30 : #include "snapwebsites/snap_string_list.h"
31 :
32 : // C++ lib
33 : //
34 : #include <iostream>
35 :
36 : // C lib
37 : //
38 : #include <uuid/uuid.h>
39 :
40 : // list include
41 : //
42 : #include <snapdev/poison.h>
43 :
44 :
45 : namespace snap
46 : {
47 :
48 : namespace
49 : {
50 0 : char hex_to_dec(ushort c)
51 : {
52 0 : if(c >= '0' && c <= '9')
53 : {
54 0 : return static_cast<char>(c - '0');
55 : }
56 0 : if(c >= 'a' && c <= 'f')
57 : {
58 0 : return static_cast<char>(c - 'a' + 10);
59 : }
60 0 : if(c >= 'A' && c <= 'F')
61 : {
62 0 : return static_cast<char>(c - 'A' + 10);
63 : }
64 0 : throw snap_exception( "error: invalid hexadecimal digit, it cannot be converted." );
65 : }
66 : }
67 :
68 :
69 0 : dbutils::dbutils( QString const & table_name, QString const & row_name )
70 : : f_tableName(table_name)
71 : , f_rowName(row_name)
72 0 : , f_displayLen(64)
73 : {
74 0 : }
75 :
76 :
77 : /** \brief Copy all the cells from one row to another.
78 : *
79 : * This function copies all the cells from one row to another. It does not
80 : * try to change anything in the process. The destination (source?) should
81 : * be tweaked as required on return.
82 : *
83 : * \warning
84 : * This function does not delete anything, if other fields already existed
85 : * in the destination, then it stays there.
86 : *
87 : * \param[in] ta The source table.
88 : * \param[in] a The name of the row to copy from.
89 : * \param[in] tb The destination table.
90 : * \param[in] b The name of the row to copy to.
91 : */
92 0 : void dbutils::copy_row(libdbproxy::table::pointer_t ta, QString const & a, // source
93 : libdbproxy::table::pointer_t tb, QString const & b) // destination
94 : {
95 : // just in case there is still a previous query, clear the cache ahead of time
96 0 : libdbproxy::row::pointer_t source_row(ta->getRow(a));
97 0 : source_row->clearCache();
98 0 : libdbproxy::row::pointer_t destination_row(tb->getRow(b));
99 0 : auto column_predicate = std::make_shared<libdbproxy::cell_range_predicate>();
100 0 : column_predicate->setCount(100); // we have to copy everything also it is likely very small (i.e. 10 fields...)
101 0 : column_predicate->setIndex(); // behave like an index
102 : for(;;)
103 : {
104 0 : source_row->readCells(column_predicate);
105 0 : libdbproxy::cells const source_cells(source_row->getCells());
106 0 : if(source_cells.isEmpty())
107 : {
108 : // done
109 0 : break;
110 : }
111 : // handle one batch
112 0 : for(libdbproxy::cells::const_iterator nc(source_cells.begin());
113 0 : nc != source_cells.end();
114 : ++nc)
115 : {
116 0 : libdbproxy::cell::pointer_t source_cell(*nc);
117 0 : QByteArray cell_key(source_cell->columnKey());
118 0 : destination_row->getCell(cell_key)->setValue(source_cell->getValue());
119 : }
120 0 : }
121 0 : }
122 :
123 :
124 :
125 0 : QByteArray dbutils::get_row_key() const
126 : {
127 0 : QByteArray row_key;
128 :
129 0 : if(!f_rowName.isEmpty() && f_tableName == "files")
130 : {
131 0 : if(f_rowName == "new" || f_rowName == "javascripts" || f_rowName == "css" || f_rowName == "images")
132 : {
133 0 : row_key = f_rowName.toLatin1();
134 : }
135 : else
136 : {
137 : // these rows make use of MD5 sums so we have to convert them
138 0 : QByteArray const str(f_rowName.toUtf8());
139 0 : char const * s(str.data());
140 0 : while(s[0] != '\0' && s[1] != '\0')
141 : {
142 0 : char const c(static_cast<char>((hex_to_dec(s[0]) << 4) | hex_to_dec(s[1])));
143 0 : row_key.append(c);
144 0 : s += 2;
145 : }
146 : }
147 : }
148 0 : else if( f_tableName == "users" )
149 : {
150 0 : libdbproxy::value const identifier(f_rowName);
151 0 : if( identifier.stringValue() == "*index_row*" || identifier.stringValue() == "*id_row*" )
152 : {
153 0 : return identifier.binaryValue();
154 : }
155 : else
156 : {
157 0 : QByteArray new_key;
158 0 : libdbproxy::appendInt64Value( new_key, static_cast<int64_t>(f_rowName.toLong()) );
159 0 : return new_key;
160 : }
161 : }
162 : else
163 : {
164 0 : row_key = f_rowName.toLatin1();
165 : }
166 :
167 0 : return row_key;
168 : }
169 :
170 :
171 : /** \brief Transform a byte in an hexadecimal number.
172 : *
173 : * This function transforms a byte (a number from 0 to 255) to an ASCII
174 : * representation using hexadecimal.
175 : *
176 : * \param[in] byte The byt to transform.
177 : *
178 : * \return The resulting string.
179 : */
180 0 : QString dbutils::byte_to_hex( char const byte )
181 : {
182 0 : const QString hex(QString("%1").arg(byte & 255, 2, 16, QChar('0')));
183 0 : return hex;
184 : }
185 :
186 :
187 : /** \brief Transform a binary key to hexadecimal.
188 : *
189 : * This function transforms each byte of a binary key to an ASCII string
190 : * of hexadecimal numbers using the byte_to_hex() function.
191 : *
192 : * \param[in] key The key to transform.
193 : *
194 : * \return The resulting string.
195 : */
196 0 : QString dbutils::key_to_string( QByteArray const & key )
197 : {
198 0 : QString ret;
199 0 : int const max_length(key.size());
200 0 : for(int i(0); i < max_length; ++i)
201 : {
202 0 : ret += byte_to_hex( key[i] );
203 : }
204 0 : return ret;
205 : }
206 :
207 :
208 0 : QByteArray dbutils::string_to_key( QString const & str )
209 : {
210 0 : QByteArray ret;
211 0 : snap_string_list numList( str.split(' ') );
212 :
213 : // TODO: we may want to seperate functions to clearly know whether
214 : // we are checking an MD5 or not
215 : //
216 0 : if(numList.size() == 1 && str.length() == 32)
217 : {
218 0 : for(int i(0); i < 32; i += 2)
219 : {
220 0 : QString val(str.mid(i, 2));
221 0 : bool ok( false );
222 0 : ret.push_back( static_cast<char>( val.toInt( &ok, 16 ) ) );
223 0 : if( !ok )
224 : {
225 0 : throw snap_exception( "Cannot convert to number! Not base 16." );
226 : }
227 : }
228 : }
229 : else
230 : {
231 0 : for( auto const & str_num : numList )
232 : {
233 0 : bool ok( false );
234 0 : ret.push_back( static_cast<char>( str_num.toInt( &ok, 16 ) ) );
235 0 : if( !ok )
236 : {
237 0 : throw snap_exception( "Cannot convert to number! Not base 16 or too large." );
238 : }
239 : }
240 : }
241 :
242 0 : return ret;
243 : }
244 :
245 :
246 0 : QString dbutils::microseconds_to_string ( int64_t const & time, bool const full )
247 : {
248 : char buf[64];
249 : struct tm t;
250 0 : time_t const seconds(time / 1000000);
251 0 : gmtime_r(&seconds, &t);
252 0 : strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
253 0 : if(full)
254 : {
255 0 : return QString("%1.%2 (%3)")
256 0 : .arg(buf)
257 0 : .arg(time % 1000000, 6, 10, QChar('0'))
258 0 : .arg(time);
259 : }
260 : else
261 : {
262 0 : return QString("%1.%2")
263 0 : .arg(buf)
264 0 : .arg(time % 1000000, 6, 10, QChar('0'));
265 : }
266 : }
267 :
268 0 : uint64_t dbutils::string_to_microseconds ( QString const & time )
269 : {
270 : // TODO: check whether we have the number between parenthesis...
271 : // The string may include the microseconds as one 64 bit number
272 : // between parenthesis; if present we may want to use that instead?
273 :
274 : // String will be of the form: "%Y-%m-%d %H:%M:%S.%N"
275 : //
276 0 : snap_string_list const datetime_split ( time.split(' ') );
277 0 : if(datetime_split.size() < 2)
278 : {
279 0 : return -1;
280 : }
281 0 : snap_string_list const date_split ( datetime_split[0].split('-') );
282 0 : snap_string_list const time_split ( datetime_split[1].split(':') );
283 0 : if(date_split.size() != 3
284 0 : || time_split.size() != 3)
285 : {
286 0 : return -1;
287 : }
288 : //
289 : tm to;
290 0 : memset(&to, 0, sizeof(to));
291 0 : to.tm_sec = time_split[2].toInt();
292 0 : to.tm_min = time_split[1].toInt();
293 0 : to.tm_hour = time_split[0].toInt();
294 0 : to.tm_mday = date_split[2].toInt();
295 0 : to.tm_mon = date_split[1].toInt() - 1;
296 0 : to.tm_year = date_split[0].toInt() - 1900;
297 :
298 0 : int64_t ns((time_split[2].toDouble() - to.tm_sec) * 1000000.0);
299 : //
300 0 : time_t const tt( mkgmtime( &to ) );
301 0 : return tt * 1000000 + ns;
302 : }
303 :
304 :
305 0 : int dbutils::get_display_len() const
306 : {
307 0 : return f_displayLen;
308 : }
309 :
310 :
311 0 : void dbutils::set_display_len( int const val )
312 : {
313 0 : f_displayLen = val;
314 0 : }
315 :
316 :
317 0 : QString dbutils::get_row_name( libdbproxy::row::pointer_t p_r ) const
318 : {
319 0 : QByteArray key(p_r->rowKey());
320 0 : return get_row_name( key );
321 : }
322 :
323 :
324 0 : QString dbutils::get_row_name( const QByteArray& key ) const
325 : {
326 0 : if(f_tableName == "files")
327 : {
328 : // these are raw MD5 keys
329 0 : if( key.size() == 16 )
330 : {
331 0 : return key_to_string( key );
332 : }
333 :
334 : // except for a few special cases
335 : // TODO: add tests to make sure only known keys do not get
336 : // defined as MD5 sums
337 : }
338 0 : else if( f_tableName == "users" )
339 : {
340 0 : libdbproxy::value const identifier(key);
341 0 : if( identifier.stringValue() == "*index_row*" || identifier.stringValue() == "*id_row*" )
342 : {
343 0 : return identifier.stringValue();
344 : }
345 : else
346 : {
347 0 : return QString("%1").arg(identifier.safeInt64Value());
348 : }
349 : }
350 :
351 0 : return QString::fromUtf8( key.data() );
352 : }
353 :
354 :
355 0 : QByteArray dbutils::set_row_name( const QString& name, const QByteArray& orig_key ) const
356 : {
357 0 : if(f_tableName == "files")
358 : {
359 : // these are raw MD5 keys
360 0 : if( orig_key.size() == 16 )
361 : {
362 0 : return string_to_key( name );
363 : }
364 : }
365 :
366 0 : return name.toUtf8();
367 : }
368 :
369 :
370 0 : QString dbutils::get_column_name( libdbproxy::cell::pointer_t c ) const
371 : {
372 0 : return get_column_name( c->columnKey() );
373 : }
374 :
375 :
376 0 : QString dbutils::get_column_name( const QByteArray& key ) const
377 : {
378 0 : QString const content_attachment_reference( "content::attachment::reference::" );
379 :
380 0 : QString name;
381 0 : if(f_tableName == "files" && f_rowName == "new")
382 : {
383 0 : name = key_to_string( key );
384 : }
385 0 : else if((f_tableName == "list" && f_rowName != "*standalone*"))
386 : {
387 0 : unsigned char priority(libdbproxy::safeUnsignedCharValue(key, 0));
388 0 : QString const time(microseconds_to_string(libdbproxy::safeInt64Value(key, sizeof(unsigned char)), true));
389 0 : name = QString("%1 %2 %3")
390 0 : .arg(static_cast<int>(priority))
391 0 : .arg(time)
392 0 : .arg(libdbproxy::stringValue(key, sizeof(unsigned char) + sizeof(uint64_t)));
393 : }
394 0 : else if((f_tableName == "files" && f_rowName == "images"))
395 : {
396 0 : QString const time(microseconds_to_string(libdbproxy::safeInt64Value(key, 0), true));
397 0 : name = QString("%1 %2").arg(time).arg(libdbproxy::stringValue(key, sizeof(uint64_t)));
398 : }
399 0 : else if(f_tableName == "branch" && (key.startsWith(content_attachment_reference.toLatin1())) )
400 : {
401 0 : name = content_attachment_reference;
402 0 : name += key_to_string( key.mid( content_attachment_reference.length() ) );
403 : }
404 0 : else if((f_tableName == "files" && f_rowName == "javascripts")
405 0 : || (f_tableName == "files" && f_rowName == "css"))
406 : {
407 : // this row name is "<name>"_"<browser>"_<version as integers>
408 0 : int const max_length(key.size());
409 0 : int sep(0);
410 0 : int i(0);
411 0 : for(; i < max_length && sep < 2; ++i)
412 : {
413 0 : if(key[i] == '_')
414 : {
415 0 : ++sep;
416 : }
417 0 : name += key[i];
418 : }
419 : // now we have to add the version
420 0 : bool first(true);
421 0 : for(; i + 3 < max_length; i += 4)
422 : {
423 0 : if(first)
424 : {
425 0 : first = false;
426 : }
427 : else
428 : {
429 0 : name += ".";
430 : }
431 0 : name += QString("%1").arg(libdbproxy::safeUInt32Value(key, i));
432 : }
433 : }
434 0 : else if( f_tableName == "users" )
435 : {
436 0 : libdbproxy::value const identifier(key);
437 0 : name = identifier.stringValue();
438 : }
439 0 : else if( (f_tableName == "shorturl" && f_rowName.endsWith("/*index_row*"))
440 0 : || f_tableName == "serverstats")
441 : {
442 : // special case where the column key is a 64 bit integer
443 0 : libdbproxy::value const identifier(key);
444 0 : name = QString("%1").arg(identifier.safeInt64Value());
445 : }
446 0 : else if(f_tableName == "tracker"
447 0 : || (f_tableName == "backend" && !f_rowName.startsWith("*"))
448 0 : || (f_tableName == "firewall" && !f_rowName.startsWith("ip::")))
449 : {
450 0 : libdbproxy::value const start_date(key);
451 0 : name = microseconds_to_string(start_date.safeInt64Value(), true);
452 : }
453 0 : else if(f_tableName == "emails" && f_rowName == "bounced_raw")
454 : {
455 0 : libdbproxy::value const start_date(key);
456 :
457 : // 64 bit value (microseconds)
458 0 : name = microseconds_to_string(start_date.safeInt64Value(), true);
459 :
460 : // 128 bit UUID
461 0 : if( static_cast<size_t>(start_date.size()) >= sizeof(int64_t) + sizeof(uuid_t) )
462 : {
463 0 : QByteArray const bytes(libdbproxy::binaryValue( start_date.binaryValue(), sizeof(int64_t), sizeof(uuid_t) ));
464 : uuid_t uuid;
465 0 : memcpy( uuid, bytes.data(), sizeof(uuid) );
466 : char unique_key[37];
467 0 : uuid_unparse( uuid, unique_key );
468 0 : name += " ";
469 0 : name += unique_key;
470 : }
471 : }
472 : else
473 : {
474 0 : name = QString::fromUtf8(key.data());
475 : }
476 :
477 0 : return name;
478 : }
479 :
480 :
481 0 : void dbutils::set_column_name( QByteArray& key, const QString& name ) const
482 : {
483 0 : QString const content_attachment_reference( "content::attachment::reference::" );
484 :
485 0 : if(f_tableName == "files" && f_rowName == "new")
486 : {
487 0 : key = string_to_key( name );
488 : }
489 0 : else if((f_tableName == "list" && f_rowName != "*standalone*"))
490 : {
491 0 : QStringList arr( name.split(' ') );
492 0 : if( arr.size() != 3 )
493 : {
494 0 : throw std::runtime_error("expected 3 arguments!");
495 : }
496 :
497 0 : const char priority = arr[0][0].toLatin1();
498 0 : libdbproxy::appendUnsignedCharValue( key, priority );
499 :
500 0 : const uint64_t microsec( string_to_microseconds( arr[1] ) );
501 0 : libdbproxy::appendInt64Value( key, microsec );
502 0 : libdbproxy::appendStringValue( key, arr[2] );
503 : }
504 0 : else if((f_tableName == "files" && f_rowName == "images"))
505 : {
506 0 : QStringList arr( name.split(' ') );
507 0 : if( arr.size() != 2 )
508 : {
509 0 : throw std::runtime_error("expected 3 arguments!");
510 : }
511 :
512 0 : const uint64_t microsec( string_to_microseconds( arr[0] ) );
513 0 : libdbproxy::appendInt64Value( key, microsec );
514 :
515 0 : libdbproxy::appendStringValue( key, arr[1] );
516 : }
517 0 : else if(f_tableName == "branch" && (name.startsWith(content_attachment_reference.toLatin1())) )
518 : {
519 0 : libdbproxy::appendStringValue( key, content_attachment_reference );
520 0 : libdbproxy::appendStringValue( key, name );
521 : }
522 0 : else if((f_tableName == "files" && f_rowName == "javascripts")
523 0 : || (f_tableName == "files" && f_rowName == "css"))
524 : {
525 : // this row name is "<name>"_"<browser>"_<version as integers>
526 0 : QStringList arr( name.split('_') );
527 0 : if( arr.size() != 3 )
528 : {
529 0 : throw std::runtime_error( "The column key is expected to be in the form: <name>_<browser>_<version>!" );
530 : }
531 :
532 0 : libdbproxy::appendStringValue( key, arr[0] + "_" ); // name
533 0 : libdbproxy::appendStringValue( key, arr[1] + "_" ); // browser
534 :
535 0 : QStringList version( arr[2].split('.') );
536 0 : for( auto rev : version )
537 : {
538 0 : libdbproxy::appendUInt32Value( key, static_cast<uint32_t>(rev.toUInt()) );
539 : }
540 : }
541 0 : else if( f_tableName == "users" )
542 : {
543 0 : libdbproxy::appendStringValue( key, name );
544 : }
545 0 : else if( (f_tableName == "shorturl" && f_rowName.endsWith("/*index_row*"))
546 0 : || f_tableName == "serverstats")
547 : {
548 0 : libdbproxy::appendInt64Value( key, static_cast<int64_t>(name.toLong()) );
549 : }
550 0 : else if(f_tableName == "tracker"
551 0 : || (f_tableName == "backend" && !f_rowName.startsWith("*"))
552 0 : || (f_tableName == "firewall" && !f_rowName.startsWith("ip::")))
553 : {
554 0 : const uint64_t microsec( string_to_microseconds( name ) );
555 0 : libdbproxy::appendInt64Value( key, microsec );
556 : }
557 0 : else if(f_tableName == "emails" && f_rowName == "bounced_raw")
558 : {
559 0 : QStringList arr( name.split(' ') );
560 0 : if( arr.size() == 2 )
561 : {
562 0 : const uint64_t microsec( string_to_microseconds( arr[0] ) );
563 0 : libdbproxy::appendInt64Value( key, microsec );
564 : //
565 : uuid_t uuid;
566 0 : uuid_parse( arr[1].toUtf8().data(), uuid );
567 : char unique_key[sizeof(uuid)];
568 0 : memcpy( unique_key, uuid, sizeof(uuid) );
569 0 : libdbproxy::appendBinaryValue( key, QByteArray(unique_key, sizeof(unique_key)) );
570 : }
571 : else
572 : {
573 0 : const uint64_t microsec( string_to_microseconds( name ) );
574 0 : libdbproxy::appendInt64Value( key, microsec );
575 : }
576 : }
577 : else
578 : {
579 0 : key = name.toUtf8();
580 : }
581 0 : }
582 :
583 :
584 0 : dbutils::column_type_t dbutils::get_column_type( libdbproxy::cell::pointer_t c ) const
585 : {
586 0 : return get_column_type( c->columnKey() );
587 : }
588 :
589 :
590 0 : dbutils::column_type_t dbutils::get_column_type( const QByteArray& key ) const
591 : {
592 0 : QString const n( get_column_name( key ) );
593 :
594 0 : if(f_tableName == "revision" && f_rowName.indexOf("#user/") != -1 && n != "content::modified")
595 : {
596 : // on error fields are all saved as string, whetever their type
597 : // (because on errors we cannot save a transformed value as the
598 : // user entered it...)
599 0 : return column_type_t::CT_string_value;
600 : }
601 :
602 0 : if(n == "antivirus::enable"
603 0 : || n == "content::breadcrumbs_show_current_page"
604 0 : || n == "content::breadcrumbs_show_home"
605 0 : || n == "content::prevent_delete"
606 0 : || n == "core::mx_result"
607 0 : || n == "core::test_site"
608 0 : || n == "core::site_secure"
609 0 : || n == "epayment_creditcard::show_address2"
610 0 : || n == "epayment_creditcard::show_country"
611 0 : || n == "epayment_creditcard::show_phone"
612 0 : || n == "epayment_creditcard::show_province"
613 0 : || n == "epayment_paypal::debug"
614 0 : || n == "epayment_stripe::debug"
615 0 : || n == "feed::allow_main_atom_xml"
616 0 : || n == "feed::allow_main_rss_xml"
617 0 : || n == "feed::publish_full_article"
618 0 : || n == "oauth2::enable"
619 0 : || n == "password::check_blacklist"
620 0 : || n == "password::exists_in_blacklist"
621 0 : || n == "permissions::dynamic"
622 0 : || n == "permissions::secure_site"
623 0 : || n == "users::example"
624 0 : || n == "users::multiuser"
625 0 : || n == "users::long_sessions"
626 0 : || n == "users::password::blocked"
627 0 : || (f_tableName == "content" && f_rowName == "*index*")
628 0 : || (f_tableName == "list" && f_rowName != "*standalone*")
629 0 : || n == "users::soft_administrative_session"
630 0 : || n == "users::verify_ignore_user_agent"
631 0 : || n == "finball::data_status" // TODO -- remove at some point since that is a cutomer's field
632 0 : || n == "finball::data_atm_holiday" // TODO -- remove at some point since that is a cutomer's field
633 0 : || n == "finball::data_cafe_holiday" // TODO -- remove at some point since that is a cutomer's field
634 0 : || n == "finball::data_carwash_holiday" // TODO -- remove at some point since that is a cutomer's field
635 0 : || n == "finball::data_carwashexpress_holiday" // TODO -- remove at some point since that is a cutomer's field
636 0 : || n == "finball::data_detailshop_holiday" // TODO -- remove at some point since that is a cutomer's field
637 0 : || n == "finball::data_giftshop_holiday" // TODO -- remove at some point since that is a cutomer's field
638 0 : || n == "finball::data_lotto_holiday" // TODO -- remove at some point since that is a cutomer's field
639 0 : || n == "finball::data_lube_holiday" // TODO -- remove at some point since that is a cutomer's field
640 0 : || n == "finball::data_propane_holiday" // TODO -- remove at some point since that is a cutomer's field
641 0 : || n == "finball::data_repair_holiday" // TODO -- remove at some point since that is a cutomer's field
642 0 : || n == "finball::data_retail_holiday" // TODO -- remove at some point since that is a cutomer's field
643 0 : || n == "finball::data_vendingmachine_holiday" // TODO -- remove at some point since that is a cutomer's field
644 0 : || n == "finball::number_of_cashiers" // TODO -- remove at some point since that is a cutomer's field
645 0 : || n == "finball::plan" // TODO -- remove at some point since that is a cutomer's field
646 0 : || n == "finball::read_terms_n_conditions" // TODO -- remove at some point since that is a customer's field (we'd need to have an XML file instead)
647 0 : || n == "finball::applies_to_companies" // TODO -- remove at some point since that is a customer's field (we'd need to have an XML file instead)
648 0 : || n == "finball::applies_to_locations" // TODO -- remove at some point since that is a customer's field (we'd need to have an XML file instead)
649 : )
650 : {
651 : // signed 8 bit value
652 0 : return column_type_t::CT_int8_value;
653 : }
654 0 : else if(n == "content::final"
655 0 : || n.startsWith("content::files::reference::")
656 0 : || n == "epayment_paypal::maximum_repeat_failures"
657 0 : || n == "sessions::used_up"
658 0 : || (f_tableName == "files" && f_rowName == "new")
659 0 : || (f_tableName == "files" && f_rowName == "images")
660 0 : || (f_tableName == "test_results" && n == "test_plugin::success")
661 0 : || (f_tableName == "processing" && n == "content::status_changed")
662 : )
663 : {
664 : // unsigned 8 bit value
665 : // cast to integer so arg() doesn't take it as a character
666 0 : return column_type_t::CT_uint8_value;
667 : }
668 0 : else if(n == "list::number_of_items"
669 0 : || (f_tableName == "domains" && f_rowName == "*test_snap_lock*" && n == "counter")
670 0 : || n == "finball::memo_count" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
671 : )
672 : {
673 0 : return column_type_t::CT_int32_value;
674 : }
675 0 : else if(n.startsWith("content::attachment::reference::")
676 0 : || n == "content::attachment::revision_control::last_branch"
677 0 : || n.startsWith("content::attachment::revision_control::last_revision::")
678 0 : || n == "content::files::image_height"
679 0 : || n == "content::files::image_width"
680 0 : || n == "content::files::size"
681 0 : || n == "content::files::size::gzip_compressed"
682 0 : || n == "content::files::size::minified"
683 0 : || n == "content::files::size::minified::gzip_compressed"
684 0 : || n == "content::revision_control::attachment::current_branch"
685 0 : || n == "content::revision_control::attachment::current_working_branch"
686 0 : || n == "content::revision_control::current_branch"
687 0 : || n == "content::revision_control::current_working_branch"
688 0 : || n == "content::revision_control::last_branch"
689 0 : || n == "content::revision_control::attachment::last_branch"
690 0 : || n.startsWith("content::revision_control::attachment::current_revision::")
691 0 : || n.startsWith("content::revision_control::attachment::current_working_revision::")
692 0 : || n.startsWith("content::revision_control::current_revision::")
693 0 : || n.startsWith("content::revision_control::current_working_revision::")
694 0 : || n.startsWith("content::revision_control::last_revision::")
695 0 : || n.startsWith("content::revision_control::attachment::last_revision::")
696 0 : || n == "sitemapxml::count"
697 0 : || n == "sessions::id"
698 0 : || n == "sessions::time_to_live"
699 0 : || (f_tableName == "lock_table" && f_rowName == "hosts")
700 : )
701 : {
702 0 : return column_type_t::CT_uint32_value;
703 : }
704 0 : else if(n == "bookkeeping::counter"
705 0 : || n == "content::revision_limits"
706 0 : || n == "cookie_consent_silktide::javascript_version"
707 0 : || n == "cookie_consent_silktide::consent_duration"
708 0 : || n == "feed::teaser_tags"
709 0 : || n == "feed::teaser_words"
710 0 : || n == "feed::top_maximum_number_of_items_in_any_feed"
711 0 : || n == "password::blocked_user_counter"
712 0 : || n == "password::blocked_user_counter_lifetime"
713 0 : || n == "password::count_failures"
714 0 : || n == "password::count_bad_password_503s"
715 0 : || n == "password::invalid_passwords_counter"
716 0 : || n == "password::invalid_passwords_block_duration"
717 0 : || n == "password::invalid_passwords_counter_lifetime"
718 0 : || n == "password::invalid_passwords_slowdown"
719 0 : || n == "password::minimum_length"
720 0 : || n == "password::minimum_length_of_variations"
721 0 : || n == "password::minimum_letters"
722 0 : || n == "password::minimum_lowercase_letters"
723 0 : || n == "password::minimum_spaces"
724 0 : || n == "password::minimum_specials"
725 0 : || n == "password::minimum_unicode"
726 0 : || n == "password::minimum_uppercase_letters"
727 0 : || n == "password::minimum_digits"
728 0 : || n == "password::minimum_variation"
729 0 : || n == "sessions::check_flags"
730 0 : || n == "users::administrative_session_duration"
731 0 : || n == "users::total_session_duration"
732 0 : || n == "users::user_session_duration"
733 0 : || (f_tableName == "firewall" && (n.endsWith("::ban_count")
734 0 : || n.endsWith("::packet_count")
735 0 : || n.endsWith("::byte_count")))
736 : )
737 : {
738 0 : return column_type_t::CT_int64_value;
739 : }
740 0 : else if(n.startsWith("content::field_priority::")
741 0 : || n == "ecommerce::invoice_number"
742 0 : || n == "epayment_paypal::invoice_number"
743 0 : || n == "shorturl::identifier"
744 0 : || n == "users::identifier"
745 0 : || n == "finball::invoice_number" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
746 0 : || n == "finball::unique_email" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
747 0 : || n == "content::journal::timestamp"
748 : )
749 : {
750 0 : return column_type_t::CT_uint64_value;
751 : }
752 0 : else if(n == "sitemapxml::priority"
753 : )
754 : {
755 : // 32 bit float
756 0 : return column_type_t::CT_float32_value;
757 : }
758 0 : else if(n == "epayment::price"
759 0 : || n == "epayment::grand_total"
760 0 : || n == "finball::atm_fee" // TODO -- remove at some point since that is a cutomer's field
761 0 : || n == "finball::company_plan1" // TODO -- remove at some point since that is a cutomer's field
762 0 : || n == "finball::company_plan12" // TODO -- remove at some point since that is a cutomer's field
763 0 : || n == "finball::company_plan6" // TODO -- remove at some point since that is a cutomer's field
764 0 : || n == "finball::location_plan1" // TODO -- remove at some point since that is a cutomer's field
765 0 : || n == "finball::location_plan12" // TODO -- remove at some point since that is a cutomer's field
766 0 : || n == "finball::location_plan6" // TODO -- remove at some point since that is a cutomer's field
767 0 : || n == "finball::lotto_fee" // TODO -- remove at some point since that is a cutomer's field
768 0 : || n == "finball::memo_invoice_total_amount" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
769 0 : || n == "finball::minimum_total" // TODO -- remove at some point since that is a cutomer's field
770 0 : || n == "finball::promotion_amount" // TODO -- remove at some point since that is a cutomer's field
771 : )
772 : {
773 : // 64 bit float
774 0 : return column_type_t::CT_float64_value;
775 : }
776 0 : else if((n.startsWith("finball::data_") && n.endsWith("_count")) // TODO -- remove at some point since that is a cutomer's field
777 0 : || (n.startsWith("finball::data_") && n.endsWith("_amount"))) // TODO -- remove at some point since that is a cutomer's field
778 : {
779 : // 64 bit float
780 0 : return column_type_t::CT_float64_or_empty_value;
781 : }
782 0 : else if((f_tableName == "backend" && f_rowName.startsWith("*"))
783 0 : || (f_tableName == "antihammering" && n == "*blocked*")
784 0 : || (f_tableName == "layout" && n.startsWith("layout::reference::"))
785 0 : || n == "content::created"
786 0 : || n == "content::cloned"
787 0 : || n == "content::files::created"
788 0 : || n == "content::files::secure::last_check"
789 0 : || n == "content::files::updated"
790 0 : || n == "content::modified"
791 0 : || n == "content::updated"
792 0 : || (f_tableName == "content" && n == "content::status_changed")
793 0 : || n.startsWith("core::last_dynamic_update")
794 0 : || n.startsWith("core::last_updated")
795 0 : || n == "core::plugin_threshold"
796 0 : || n == "core::site_ready"
797 0 : || n == "editor::date_edit_widget"
798 0 : || n == "editor::dropdown_date_edit_widget"
799 0 : || n == "epayment_paypal::last_attempt"
800 0 : || n == "epayment_paypal::oauth2_expires"
801 0 : || n == "epayment_stripe::created"
802 0 : || n == "content::files::creation_time"
803 0 : || n == "content::files::modification_time"
804 0 : || n == "core::mx_last_checked"
805 0 : || n == "images::modified"
806 0 : || n == "list::last_updated"
807 0 : || n == "permissions::last_updated"
808 0 : || n == "sendmail::bounce_arrival_date0"
809 0 : || n == "sendmail::bounce_arrival_date1"
810 0 : || n == "sendmail::bounce_arrival_date2"
811 0 : || n == "sendmail::bounce_arrival_date3"
812 0 : || n == "sendmail::bounce_arrival_date4"
813 0 : || n.endsWith("::sendmail::created")
814 0 : || (f_tableName == "firewall" && (n.endsWith("::created")
815 0 : || n.endsWith("::modified")
816 0 : || n.endsWith("::block_limit")))
817 0 : || n == "sendmail::unsubscribe_on"
818 0 : || n == "sessions::date"
819 0 : || n == "snap_software_description::last_update"
820 0 : || n == "shorturl::date"
821 0 : || n == "users::created_time"
822 0 : || n == "users::forgot_password_on"
823 0 : || n == "users::login_on"
824 0 : || n == "users::logout_on"
825 0 : || n == "users::modified"
826 0 : || n == "users::password::modified"
827 0 : || n.startsWith("users::password::modified_")
828 0 : || n == "users::previous_login_on"
829 0 : || n == "users::start_date"
830 0 : || n == "users::verified_on"
831 0 : || (f_tableName == "users" && n.startsWith("users::website_reference::"))
832 0 : || n == "sessions::creation_date"
833 0 : || (f_tableName == "test_results" && n == "test_plugin::end_date")
834 0 : || (f_tableName == "test_results" && n == "test_plugin::start_date")
835 0 : || n == "finball::applied_on" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
836 0 : || n == "finball::apply_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
837 0 : || n == "finball::billing_last_updated" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
838 0 : || n == "finball::category_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
839 0 : || n == "finball::correct_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
840 0 : || n == "finball::data_last_modified" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
841 0 : || n == "finball::end_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
842 0 : || n == "finball::payment_entered_on" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
843 0 : || n == "finball::sub_category_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
844 0 : || n == "finball::business_type_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
845 0 : || n == "finball::connection_accepted_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
846 0 : || n == "finball::connection_declined_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
847 0 : || n == "finball::invoice_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
848 0 : || n == "finball::invoice_due_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
849 0 : || n == "finball::invoice_end_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
850 0 : || n == "finball::invoice_paid_on" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
851 0 : || n == "finball::invoice_start_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
852 0 : || n == "finball::memo_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
853 0 : || n == "finball::memo_end_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
854 0 : || n == "finball::memo_paid_on" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
855 0 : || n == "finball::memo_start_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
856 0 : || n == "finball::payment_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
857 0 : || n == "finball::refused_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
858 0 : || n == "finball::report_created" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
859 0 : || n == "finball::start_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
860 0 : || n == "finball::void_date" // TODO -- remove at some point since that is a customer's type (we'd need to have an XML file instead)
861 : )
862 : {
863 : // 64 bit value (microseconds)
864 0 : return column_type_t::CT_time_microseconds;
865 : }
866 0 : else if(n == "sessions::login_limit"
867 0 : || n == "sessions::time_limit"
868 : )
869 : {
870 : // 64 bit value (seconds)
871 0 : return column_type_t::CT_time_seconds;
872 : }
873 0 : else if(f_tableName == "listref"
874 : )
875 : {
876 0 : return column_type_t::CT_priority_and_time_microseconds_and_string;
877 : }
878 0 : else if(n == "sessions::random"
879 0 : || n == "users::password::salt"
880 0 : || n.startsWith("users::password::salt_")
881 0 : || n == "users::password"
882 0 : || n.startsWith("users::password_")
883 : )
884 : {
885 : // n bit binary value
886 0 : return column_type_t::CT_hexarray_value;
887 : }
888 0 : else if(n.startsWith("content::files::data")
889 0 : || f_tableName == "layout"
890 0 : || n.startsWith("finball::mtd_data_") // TODO -- remove at some point since that is a cutomer's field
891 : )
892 : {
893 : // n bit binary value
894 : // same as previous only this can be huge so we limit it
895 0 : return column_type_t::CT_hexarray_limited_value;
896 : }
897 0 : else if((f_tableName == "revision" && n == "content::attachment")
898 0 : || (f_tableName == "files" && f_rowName == "javascripts")
899 0 : || (f_tableName == "files" && f_rowName == "css")
900 : )
901 : {
902 : // md5 in binary
903 0 : return column_type_t::CT_md5array_value;
904 : }
905 0 : else if(n == "content::files::secure")
906 : {
907 0 : return column_type_t::CT_secure_value;
908 : }
909 0 : else if(n == "content::status")
910 : {
911 0 : return column_type_t::CT_status_value;
912 : }
913 0 : else if(f_tableName == "cache"
914 0 : && (n.startsWith("permissions::")))
915 : {
916 0 : return column_type_t::CT_rights_value;
917 : }
918 0 : else if( (f_tableName == "users") && (f_rowName == "*index_row*") )
919 : {
920 0 : return column_type_t::CT_int64_value;
921 : }
922 :
923 : // all others viewed as strings
924 0 : return column_type_t::CT_string_value;
925 : }
926 :
927 :
928 0 : dbutils::column_type_t dbutils::get_column_type( QString const & name )
929 : {
930 0 : if(name.isEmpty())
931 : {
932 0 : throw snap_exception( "error: get_column_type() can't be called with an empty column name" );
933 : }
934 :
935 0 : switch(name[0].unicode())
936 : {
937 0 : case 'b':
938 0 : if(name == "binary") // replacement of CT_hexarray and CT_hexarray_limited
939 : {
940 0 : return column_type_t::CT_binary_value;
941 : }
942 0 : break;
943 :
944 0 : case 'f':
945 0 : if(name == "float32")
946 : {
947 0 : return column_type_t::CT_float32_value;
948 : }
949 0 : if(name == "float64")
950 : {
951 0 : return column_type_t::CT_float64_value;
952 : }
953 0 : break;
954 :
955 0 : case 'i':
956 0 : if(name == "int8")
957 : {
958 0 : return column_type_t::CT_int8_value;
959 : }
960 0 : if(name == "int16")
961 : {
962 0 : return column_type_t::CT_int16_value;
963 : }
964 0 : if(name == "int32")
965 : {
966 0 : return column_type_t::CT_int32_value;
967 : }
968 0 : if(name == "int64")
969 : {
970 0 : return column_type_t::CT_int64_value;
971 : }
972 0 : break;
973 :
974 0 : case 's':
975 0 : if(name == "string")
976 : {
977 0 : return column_type_t::CT_string_value;
978 : }
979 0 : break;
980 :
981 0 : case 't':
982 0 : if(name == "time_microseconds")
983 : {
984 0 : return column_type_t::CT_time_microseconds;
985 : }
986 0 : if(name == "time_seconds")
987 : {
988 0 : return column_type_t::CT_time_seconds;
989 : }
990 0 : break;
991 :
992 0 : case 'u':
993 0 : if(name == "uint8")
994 : {
995 0 : return column_type_t::CT_uint8_value;
996 : }
997 0 : if(name == "uint16")
998 : {
999 0 : return column_type_t::CT_uint16_value;
1000 : }
1001 0 : if(name == "uint32")
1002 : {
1003 0 : return column_type_t::CT_uint32_value;
1004 : }
1005 0 : if(name == "uint64")
1006 : {
1007 0 : return column_type_t::CT_uint64_value;
1008 : }
1009 0 : break;
1010 :
1011 : }
1012 :
1013 0 : throw snap_exception( "error: get_column_type() doesn't know about type " + std::string(name.toUtf8().data()) );
1014 : }
1015 :
1016 :
1017 0 : QString dbutils::get_column_type_name( column_type_t val )
1018 : {
1019 0 : QString name;
1020 0 : switch( val )
1021 : {
1022 0 : case column_type_t::CT_int8_value : name = "int8" ; break;
1023 0 : case column_type_t::CT_uint8_value : name = "uint8" ; break;
1024 0 : case column_type_t::CT_int16_value : name = "int16" ; break;
1025 0 : case column_type_t::CT_uint16_value : name = "uint16" ; break;
1026 0 : case column_type_t::CT_int32_value : name = "int32" ; break;
1027 0 : case column_type_t::CT_uint32_value : name = "uint32" ; break;
1028 0 : case column_type_t::CT_int64_value : name = "int64" ; break;
1029 0 : case column_type_t::CT_uint64_value : name = "uint64" ; break;
1030 0 : case column_type_t::CT_float32_value : name = "float32" ; break;
1031 0 : case column_type_t::CT_float64_value : name = "float64" ; break;
1032 0 : case column_type_t::CT_float64_or_empty_value : name = "float64_or_empty" ; break;
1033 0 : case column_type_t::CT_time_microseconds : name = "time_microseconds" ; break;
1034 0 : case column_type_t::CT_time_seconds : name = "time_seconds" ; break;
1035 0 : case column_type_t::CT_time_microseconds_and_string : name = "time_microseconds_and_string" ; break;
1036 0 : case column_type_t::CT_priority_and_time_microseconds_and_string : name = "priority_and_time_microseconds_and_string" ; break;
1037 0 : case column_type_t::CT_hexarray_value : name = "hexarray" ; break;
1038 0 : case column_type_t::CT_hexarray_limited_value : name = "hexarray_limited" ; break;
1039 0 : case column_type_t::CT_md5array_value : name = "md5array" ; break;
1040 0 : case column_type_t::CT_secure_value : name = "secure" ; break;
1041 0 : case column_type_t::CT_status_value : name = "status" ; break;
1042 0 : case column_type_t::CT_string_value : name = "string" ; break;
1043 0 : case column_type_t::CT_rights_value : name = "rights" ; break;
1044 0 : case column_type_t::CT_binary_value : name = "binary" ; break;
1045 : }
1046 0 : return name;
1047 : }
1048 :
1049 :
1050 0 : QString dbutils::get_column_type_name( const QByteArray& key ) const
1051 : {
1052 0 : return get_column_type_name( get_column_type(key) );
1053 : }
1054 :
1055 :
1056 0 : QString dbutils::get_column_value( libdbproxy::cell::pointer_t c, bool const display_only ) const
1057 : {
1058 0 : return get_column_value( c->columnKey(), c->getValue().binaryValue(), display_only );
1059 : }
1060 :
1061 :
1062 0 : QString dbutils::get_column_value( const QByteArray& key, const QByteArray& value, bool const display_only ) const
1063 : {
1064 0 : libdbproxy::value cvalue(value);
1065 0 : return get_column_value( key, cvalue, display_only );
1066 : }
1067 :
1068 0 : QString dbutils::get_column_value( const QByteArray& key, const libdbproxy::value& value, bool const display_only ) const
1069 : {
1070 0 : QString v;
1071 : try
1072 : {
1073 0 : column_type_t const ct( get_column_type( key ) );
1074 0 : switch( ct )
1075 : {
1076 0 : case column_type_t::CT_int8_value:
1077 : {
1078 : // signed 8 bit value
1079 : // cast to integer so arg() doesn't take it as a character
1080 0 : v = QString("%1").arg(static_cast<int>(value.signedCharValue()));
1081 : }
1082 0 : break;
1083 :
1084 0 : case column_type_t::CT_uint8_value:
1085 : {
1086 : // unsigned 8 bit value
1087 : // cast to integer so arg() doesn't take it as a character
1088 0 : v = QString("%1").arg(static_cast<int>(value.unsignedCharValue()));
1089 : }
1090 0 : break;
1091 :
1092 0 : case column_type_t::CT_int16_value:
1093 : {
1094 : // 16 bit value
1095 0 : v = QString("%1").arg(value.int16Value());
1096 : }
1097 0 : break;
1098 :
1099 0 : case column_type_t::CT_uint16_value:
1100 : {
1101 : // 16 bit value
1102 0 : v = QString("%1").arg(value.uint16Value());
1103 : }
1104 0 : break;
1105 :
1106 0 : case column_type_t::CT_int32_value:
1107 : {
1108 : // 32 bit value
1109 0 : v = QString("%1").arg(value.int32Value());
1110 : }
1111 0 : break;
1112 :
1113 0 : case column_type_t::CT_uint32_value:
1114 : {
1115 : // 32 bit value
1116 0 : v = QString("%1").arg(value.uint32Value());
1117 : }
1118 0 : break;
1119 :
1120 0 : case column_type_t::CT_int64_value:
1121 : {
1122 0 : v = QString("%1").arg(value.int64Value());
1123 : }
1124 0 : break;
1125 :
1126 0 : case column_type_t::CT_uint64_value:
1127 : {
1128 0 : v = QString("%1").arg(value.uint64Value());
1129 : }
1130 0 : break;
1131 :
1132 0 : case column_type_t::CT_float32_value:
1133 : {
1134 : // 32 bit float
1135 0 : v = QString("%1").arg(value.floatValue());
1136 : }
1137 0 : break;
1138 :
1139 0 : case column_type_t::CT_float64_value:
1140 : {
1141 : // 64 bit float
1142 0 : v = QString("%1").arg(value.doubleValue());
1143 : }
1144 0 : break;
1145 :
1146 0 : case column_type_t::CT_float64_or_empty_value:
1147 : {
1148 : // 64 bit float or empty
1149 0 : if(value.nullValue())
1150 : {
1151 0 : v = "";
1152 : }
1153 : else
1154 : {
1155 0 : v = QString("%1").arg(value.doubleValue());
1156 : }
1157 : }
1158 0 : break;
1159 :
1160 0 : case column_type_t::CT_time_microseconds:
1161 : {
1162 : // 64 bit value (microseconds)
1163 0 : int64_t const time(value.safeInt64Value());
1164 0 : if(time == 0)
1165 : {
1166 0 : v = "time not set (0)";
1167 : }
1168 : else
1169 : {
1170 0 : v = microseconds_to_string(time, true);
1171 0 : }
1172 : }
1173 0 : break;
1174 :
1175 0 : case column_type_t::CT_time_microseconds_and_string:
1176 : {
1177 0 : v = QString("%1 %2")
1178 0 : .arg(microseconds_to_string(libdbproxy::safeInt64Value(value.binaryValue(), 0), true))
1179 0 : .arg(libdbproxy::stringValue(value.binaryValue(), sizeof(int64_t)));
1180 : }
1181 0 : break;
1182 :
1183 0 : case column_type_t::CT_priority_and_time_microseconds_and_string:
1184 : {
1185 0 : v = QString("%1 %2 %3")
1186 0 : .arg(static_cast<int>(libdbproxy::safeUnsignedCharValue(value.binaryValue(), 0)))
1187 0 : .arg(microseconds_to_string(libdbproxy::safeInt64Value(value.binaryValue(), sizeof(unsigned char)), true))
1188 0 : .arg(libdbproxy::stringValue(value.binaryValue(), sizeof(unsigned char) + sizeof(int64_t)));
1189 : }
1190 0 : break;
1191 :
1192 0 : case column_type_t::CT_time_seconds:
1193 : {
1194 : // 64 bit value (seconds)
1195 0 : uint64_t time(value.uint64Value());
1196 0 : if(time == 0)
1197 : {
1198 0 : v = "time not set (0)";
1199 : }
1200 : else
1201 : {
1202 : char buf[64];
1203 : struct tm t;
1204 0 : time_t const seconds(time);
1205 0 : gmtime_r(&seconds, &t);
1206 0 : strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
1207 0 : v = display_only
1208 0 : ? QString("%1 (%2)").arg(buf).arg(time)
1209 0 : : QString("%1").arg(buf);
1210 : }
1211 : }
1212 0 : break;
1213 :
1214 0 : case column_type_t::CT_binary_value:
1215 : case column_type_t::CT_hexarray_value:
1216 : case column_type_t::CT_hexarray_limited_value:
1217 : {
1218 : // n bit binary value
1219 0 : bool const display_limited( display_only && (ct == column_type_t::CT_hexarray_limited_value) );
1220 0 : const QByteArray& buf(value.binaryValue());
1221 0 : int const max_length( display_limited ? std::min(f_displayLen, buf.size()): buf.size() );
1222 0 : if( display_only )
1223 : {
1224 0 : v += "(hex) ";
1225 : }
1226 0 : for(int i(0); i < max_length; ++i)
1227 : {
1228 0 : v += byte_to_hex(buf[i]) + " ";
1229 : }
1230 0 : if( display_limited && (buf.size() > max_length) )
1231 : {
1232 0 : v += "...";
1233 : }
1234 : }
1235 0 : break;
1236 :
1237 0 : case column_type_t::CT_md5array_value:
1238 : {
1239 : // md5 in binary
1240 0 : QByteArray const& buf(value.binaryValue());
1241 0 : if( display_only )
1242 : {
1243 0 : v += "(md5) ";
1244 : }
1245 0 : v += key_to_string(buf);
1246 : }
1247 0 : break;
1248 :
1249 0 : case column_type_t::CT_secure_value:
1250 : {
1251 0 : switch(value.signedCharValue())
1252 : {
1253 0 : case -1:
1254 0 : v = "not checked (-1)";
1255 0 : break;
1256 :
1257 0 : case 0:
1258 0 : v = "not secure (0)";
1259 0 : break;
1260 :
1261 0 : case 1:
1262 0 : v = "secure (1)";
1263 0 : break;
1264 :
1265 0 : default:
1266 0 : v = QString("unknown secure status (%1)").arg(value.signedCharValue());
1267 0 : break;
1268 :
1269 : }
1270 : }
1271 0 : break;
1272 :
1273 0 : case column_type_t::CT_status_value:
1274 : {
1275 0 : uint32_t status(value.uint32Value());
1276 0 : if(display_only)
1277 : {
1278 0 : switch(status & 0x000000FF)
1279 : {
1280 0 : case 0:
1281 0 : v = "unknown state";
1282 0 : break;
1283 :
1284 0 : case 1:
1285 0 : v = "create"; // should not be saved!
1286 0 : break;
1287 :
1288 0 : case 2:
1289 0 : v = "normal";
1290 0 : break;
1291 :
1292 0 : case 3:
1293 0 : v = "hidden";
1294 0 : break;
1295 :
1296 0 : case 4:
1297 0 : v = "moved";
1298 0 : break;
1299 :
1300 0 : case 5:
1301 0 : v = "deleted";
1302 0 : break;
1303 :
1304 0 : default:
1305 0 : v = QString("unknown content status (%1)").arg(status & 255);
1306 0 : break;
1307 :
1308 : }
1309 : // working is not supported anymore
1310 : //switch(status & 0x0000FF00)
1311 : //{
1312 : //case 0 * 256:
1313 : // v += " (unknown working)";
1314 : // break;
1315 :
1316 : //case 1 * 256:
1317 : // // "not working" is not shown
1318 : // break;
1319 :
1320 : //case 2 * 256:
1321 : // v += " (creating)";
1322 : // break;
1323 :
1324 : //case 3 * 256:
1325 : // v += " (cloning)";
1326 : // break;
1327 :
1328 : //case 4 * 256:
1329 : // v += " (removing)";
1330 : // break;
1331 :
1332 : //case 5 * 256:
1333 : // v += " (updating)";
1334 : // break;
1335 :
1336 : //default:
1337 : // v += QString(" (unknown working status: %1)").arg(status & 0x0000FF00);
1338 : // break;
1339 :
1340 : //}
1341 : }
1342 : else
1343 : {
1344 : //v = QString("%1 (%2)").arg(status & 255).arg((status / 256) & 255);
1345 0 : v = QString("%1").arg(status & 0x000000FF);
1346 : }
1347 : }
1348 0 : break;
1349 :
1350 0 : case column_type_t::CT_string_value:
1351 : {
1352 0 : v = value.stringValue().replace("\r", "\\r").replace("\n", "\\n");
1353 : }
1354 0 : break;
1355 :
1356 0 : case column_type_t::CT_rights_value:
1357 : {
1358 : // save the time followed by the list of permissions separated
1359 : // by '\n'
1360 0 : v = QString("%1 %2")
1361 0 : .arg(microseconds_to_string(value.safeInt64Value(), true))
1362 0 : .arg(value.stringValue(sizeof(int64_t)).replace("\r", "\\r").replace("\n", "\\n"));
1363 : }
1364 0 : break;
1365 :
1366 : }
1367 : }
1368 0 : catch(std::runtime_error const& e)
1369 : {
1370 0 : SNAP_LOG_ERROR() << "error: caught a runtime exception dealing with \"" << get_column_name(key) << "\" (" << e.what() << ")";
1371 : // TBD: just rethrow?
1372 : //throw;
1373 0 : v = "ERROR DETECTED";
1374 : }
1375 :
1376 0 : return v;
1377 : }
1378 :
1379 :
1380 0 : void dbutils::set_column_value( libdbproxy::cell::pointer_t c, QString const & v ) const
1381 : {
1382 0 : libdbproxy::value cvalue;
1383 0 : set_column_value( c->columnKey(), cvalue, v );
1384 0 : c->setValue( cvalue );
1385 0 : }
1386 :
1387 :
1388 0 : void dbutils::set_column_value( const QByteArray& key, QByteArray& value, QString const & v ) const
1389 : {
1390 0 : libdbproxy::value cvalue;
1391 0 : set_column_value( key, cvalue, v );
1392 0 : value = cvalue.binaryValue();
1393 0 : }
1394 :
1395 :
1396 0 : void dbutils::set_column_value( const QByteArray& key, libdbproxy::value& cvalue, QString const & v ) const
1397 : {
1398 0 : switch( get_column_type( key ) )
1399 : {
1400 0 : case column_type_t::CT_int8_value:
1401 : {
1402 0 : cvalue.setSignedCharValue( static_cast<signed char>(v.toInt()) );
1403 : }
1404 0 : break;
1405 :
1406 0 : case column_type_t::CT_uint8_value:
1407 : {
1408 0 : cvalue.setUnsignedCharValue( static_cast<unsigned char>(v.toUInt()) );
1409 : }
1410 0 : break;
1411 :
1412 0 : case column_type_t::CT_int16_value:
1413 : {
1414 0 : cvalue.setInt16Value( static_cast<signed char>(v.toInt()) );
1415 : }
1416 0 : break;
1417 :
1418 0 : case column_type_t::CT_uint16_value:
1419 : {
1420 0 : cvalue.setUInt16Value( static_cast<unsigned char>(v.toUInt()) );
1421 : }
1422 0 : break;
1423 :
1424 0 : case column_type_t::CT_int32_value:
1425 : {
1426 0 : cvalue.setInt32Value( static_cast<int32_t>(v.toLong()) );
1427 : }
1428 0 : break;
1429 :
1430 0 : case column_type_t::CT_uint32_value:
1431 : {
1432 0 : cvalue.setUInt32Value( static_cast<uint32_t>(v.toULong()) );
1433 : }
1434 0 : break;
1435 :
1436 0 : case column_type_t::CT_int64_value:
1437 : {
1438 0 : cvalue.setInt64Value( static_cast<uint64_t>(v.toLongLong()) );
1439 : }
1440 0 : break;
1441 :
1442 0 : case column_type_t::CT_uint64_value:
1443 : {
1444 0 : cvalue.setUInt64Value( static_cast<uint64_t>(v.toULongLong()) );
1445 : }
1446 0 : break;
1447 :
1448 0 : case column_type_t::CT_float32_value:
1449 : {
1450 0 : cvalue.setFloatValue( v.toFloat() );
1451 : }
1452 0 : break;
1453 :
1454 0 : case column_type_t::CT_float64_value:
1455 : {
1456 0 : cvalue.setFloatValue( v.toDouble() );
1457 : }
1458 0 : break;
1459 :
1460 0 : case column_type_t::CT_float64_or_empty_value:
1461 : {
1462 0 : if(v.isEmpty())
1463 : {
1464 0 : cvalue.setStringValue( "" );
1465 : }
1466 : else
1467 : {
1468 0 : cvalue.setFloatValue( v.toDouble() );
1469 : }
1470 : }
1471 0 : break;
1472 :
1473 0 : case column_type_t::CT_time_microseconds:
1474 : {
1475 0 : cvalue.setInt64Value( string_to_microseconds(v) );
1476 : }
1477 0 : break;
1478 :
1479 0 : case column_type_t::CT_time_microseconds_and_string:
1480 : {
1481 : // String will be of the form: "%Y-%m-%d %H:%M:%S.%N string"
1482 : //
1483 0 : snap_string_list datetime_split ( v.split(' ') );
1484 0 : if(datetime_split.size() < 2)
1485 : {
1486 0 : return;
1487 : }
1488 0 : snap_string_list const date_split ( datetime_split[0].split('-') );
1489 0 : snap_string_list const time_split ( datetime_split[1].split(':') );
1490 0 : if(date_split.size() != 3)
1491 : {
1492 0 : return;
1493 : }
1494 0 : if(time_split.size() != 3)
1495 : {
1496 0 : return;
1497 : }
1498 0 : datetime_split.removeFirst();
1499 0 : datetime_split.removeFirst();
1500 0 : QString const str(datetime_split.join(" "));
1501 : //
1502 : tm to;
1503 0 : to.tm_sec = time_split[2].toInt();
1504 0 : to.tm_min = time_split[1].toInt();
1505 0 : to.tm_hour = time_split[0].toInt();
1506 0 : to.tm_mday = date_split[2].toInt();
1507 0 : to.tm_mon = date_split[1].toInt() - 1;
1508 0 : to.tm_year = date_split[0].toInt() - 1900; // TODO handle the microseconds decimal number
1509 :
1510 0 : int64_t ns((time_split[2].toDouble() - to.tm_sec) * 1000000.0);
1511 : //
1512 0 : time_t const tt( mkgmtime( &to ) );
1513 :
1514 : // concatenate the result
1515 0 : QByteArray tms;
1516 0 : libdbproxy::appendInt64Value( tms, tt * 1000000 + ns );
1517 0 : libdbproxy::appendStringValue( tms, str );
1518 0 : cvalue.setBinaryValue(tms);
1519 : }
1520 0 : break;
1521 :
1522 0 : case column_type_t::CT_priority_and_time_microseconds_and_string:
1523 : {
1524 : // String will be of the form: "priority %Y-%m-%d %H:%M:%S.%N string"
1525 : //
1526 0 : snap_string_list datetime_split ( v.split(' ') );
1527 0 : if(datetime_split.size() < 3)
1528 : {
1529 0 : return;
1530 : }
1531 0 : QString const priority_str ( datetime_split[0] );
1532 0 : snap_string_list const date_split ( datetime_split[1].split('-') );
1533 0 : snap_string_list const time_split ( datetime_split[2].split(':') );
1534 :
1535 0 : bool ok(false);
1536 0 : int priority(priority_str.toInt(&ok, 10));
1537 0 : if(!ok)
1538 : {
1539 0 : return;
1540 : }
1541 0 : if(date_split.size() != 3)
1542 : {
1543 0 : return;
1544 : }
1545 0 : if(time_split.size() != 3)
1546 : {
1547 0 : return;
1548 : }
1549 :
1550 0 : datetime_split.removeFirst();
1551 0 : datetime_split.removeFirst();
1552 0 : datetime_split.removeFirst();
1553 0 : QString const str(datetime_split.join(" "));
1554 : //
1555 : tm to;
1556 0 : to.tm_sec = time_split[2].toInt();
1557 0 : to.tm_min = time_split[1].toInt();
1558 0 : to.tm_hour = time_split[0].toInt();
1559 0 : to.tm_mday = date_split[2].toInt();
1560 0 : to.tm_mon = date_split[1].toInt() - 1;
1561 0 : to.tm_year = date_split[0].toInt() - 1900; // TODO handle the microseconds decimal number
1562 :
1563 0 : int64_t ns((time_split[2].toDouble() - to.tm_sec) * 1000000.0);
1564 : //
1565 0 : time_t const tt( mkgmtime( &to ) );
1566 :
1567 : // concatenate the result
1568 0 : QByteArray tms;
1569 0 : libdbproxy::appendUnsignedCharValue( tms, static_cast<unsigned char>(priority) );
1570 0 : libdbproxy::appendInt64Value( tms, tt * 1000000 + ns );
1571 0 : libdbproxy::appendStringValue( tms, str );
1572 0 : cvalue.setBinaryValue(tms);
1573 : }
1574 0 : break;
1575 :
1576 0 : case column_type_t::CT_time_seconds:
1577 : {
1578 : // String will be of the form: "%Y-%m-%d %H:%M:%S"
1579 : //
1580 0 : snap_string_list const datetime_split ( v.split(' ') );
1581 0 : if(datetime_split.size() < 2)
1582 : {
1583 0 : return;
1584 : }
1585 0 : snap_string_list const date_split ( datetime_split[0].split('-') );
1586 0 : snap_string_list const time_split ( datetime_split[1].split(':') );
1587 0 : if(date_split.size() != 3)
1588 : {
1589 0 : return;
1590 : }
1591 0 : if(time_split.size() != 3)
1592 : {
1593 0 : return;
1594 : }
1595 : //
1596 : tm to;
1597 0 : to.tm_sec = time_split[2].toInt();
1598 0 : to.tm_min = time_split[1].toInt();
1599 0 : to.tm_hour = time_split[0].toInt();
1600 0 : to.tm_mday = date_split[2].toInt();
1601 0 : to.tm_mon = date_split[1].toInt() - 1;
1602 0 : to.tm_year = date_split[0].toInt() - 1900;
1603 : //
1604 0 : time_t const tt( mkgmtime( &to ) );
1605 0 : cvalue.setUInt64Value( tt );
1606 : }
1607 0 : break;
1608 :
1609 0 : case column_type_t::CT_binary_value:
1610 : case column_type_t::CT_hexarray_value:
1611 : case column_type_t::CT_hexarray_limited_value:
1612 : {
1613 0 : cvalue.setBinaryValue( string_to_key( v ) );
1614 : }
1615 0 : break;
1616 :
1617 0 : case column_type_t::CT_md5array_value:
1618 : {
1619 0 : cvalue.setBinaryValue( string_to_key( v ) );
1620 : }
1621 0 : break;
1622 :
1623 0 : case column_type_t::CT_secure_value:
1624 : {
1625 : signed char cv;
1626 0 : if( v == "not checked (-1)" || v == "-1" )
1627 : {
1628 0 : cv = -1;
1629 : }
1630 0 : else if( v == "not secure (0)" || v == "0" )
1631 : {
1632 0 : cv = 0;
1633 : }
1634 0 : else if( v == "secure (1)" || v == "1" )
1635 : {
1636 0 : cv = 1;
1637 : }
1638 : else
1639 : {
1640 0 : throw snap_exception( "error: unknown secure value! Must be -1, 0 or 1!" );
1641 : }
1642 0 : cvalue.setSignedCharValue( cv );
1643 : }
1644 0 : break;
1645 :
1646 0 : case column_type_t::CT_status_value:
1647 : {
1648 : uint32_t cv;
1649 0 : QString state_name(v);
1650 : //int pos(v.indexOf("("));
1651 : //if(pos != -1)
1652 : //{
1653 : // state_name = state_name.left(pos).trimmed();
1654 : //}
1655 0 : state_name = state_name.trimmed();
1656 0 : if(state_name == "0" || state_name == "unknown" || state_name == "unknown state")
1657 : {
1658 0 : cv = 0;
1659 : }
1660 0 : else if(state_name == "1" || state_name == "create")
1661 : {
1662 0 : cv = 1;
1663 : }
1664 0 : else if(state_name == "2" || state_name == "normal")
1665 : {
1666 0 : cv = 2;
1667 : }
1668 0 : else if(state_name == "3" || state_name == "hidden")
1669 : {
1670 0 : cv = 3;
1671 : }
1672 0 : else if(state_name == "4" || state_name == "moved")
1673 : {
1674 0 : cv = 4;
1675 : }
1676 0 : else if(state_name == "5" || state_name == "deleted")
1677 : {
1678 0 : cv = 5;
1679 : }
1680 : else
1681 : {
1682 0 : throw snap_exception( "error: unknown status state value! Must be between 0 and +5 or a valid name!" );
1683 : }
1684 : //if(pos != -1)
1685 : //{
1686 : // // there is processing status
1687 : // QString working_name(v.mid(pos + 1).trimmed());
1688 : // if(working_name.right(1) == ")")
1689 : // {
1690 : // working_name.remove(working_name.length() - 1, 1);
1691 : // }
1692 : // if(working_name == "0" || working_name == "unknown" || working_name == "unknown working")
1693 : // {
1694 : // cv |= 0 * 256;
1695 : // }
1696 : // else if(working_name == "1" || working_name == "not working")
1697 : // {
1698 : // cv |= 1 * 256;
1699 : // }
1700 : // else if(working_name == "2" || working_name == "creating")
1701 : // {
1702 : // cv |= 2 * 256;
1703 : // }
1704 : // else if(working_name == "3" || working_name == "cloning")
1705 : // {
1706 : // cv |= 3 * 256;
1707 : // }
1708 : // else if(working_name == "4" || working_name == "removing")
1709 : // {
1710 : // cv |= 4 * 256;
1711 : // }
1712 : // else if(working_name == "5" || working_name == "updating")
1713 : // {
1714 : // cv |= 5 * 256;
1715 : // }
1716 : //}
1717 : //else
1718 : //{
1719 : // // use not working by default
1720 : // cv |= 1 * 256;
1721 : //}
1722 0 : cvalue.setUInt32Value( cv );
1723 : }
1724 0 : break;
1725 :
1726 0 : case column_type_t::CT_string_value:
1727 : {
1728 : // all others viewed as strings
1729 : //v = c->getValue().stringValue().replace("\n", "\\n");
1730 0 : QString convert( v );
1731 0 : cvalue.setStringValue( convert.replace( "\\r", "\r" ).replace( "\\n", "\n" ) );
1732 : }
1733 0 : break;
1734 :
1735 0 : case column_type_t::CT_rights_value:
1736 : {
1737 : // save the time followed by the list of permissions separated
1738 : // by '\n'
1739 0 : QString convert( v );
1740 0 : QByteArray buffer;
1741 0 : libdbproxy::setInt64Value( buffer, string_to_microseconds(v) );
1742 0 : int pos(v.indexOf(')'));
1743 0 : if(pos > 0)
1744 : {
1745 0 : ++pos;
1746 0 : while(v[pos].isSpace())
1747 : {
1748 0 : ++pos;
1749 : }
1750 0 : libdbproxy::appendStringValue( buffer, v.mid(pos + 1) );
1751 : }
1752 0 : cvalue.setBinaryValue(buffer);
1753 : }
1754 0 : break;
1755 : }
1756 : }
1757 :
1758 :
1759 6 : }
1760 : // namespace snap
1761 :
1762 : // vim: ts=4 sw=4 et
|