You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1828 rivejä
54 KiB

  1. #include <string>
  2. #include <iostream>
  3. #include <cpputils/misc/enum.h>
  4. #include <cpputils/misc/string.h>
  5. #include <cpputils/misc/indent.h>
  6. #include <cpphibernate/misc.h>
  7. #include <cpphibernate/driver/mariadb/schema/table.h>
  8. #include <cpphibernate/driver/mariadb/schema/filter.inl>
  9. using namespace ::utl;
  10. using namespace ::cpphibernate;
  11. using namespace ::cpphibernate::driver::mariadb_impl;
  12. /* data_extractor_t */
  13. struct foreign_many_tuple_t
  14. {
  15. const field_t& field;
  16. read_context_ptr context;
  17. std::string owner;
  18. };
  19. struct foreign_many_list_t :
  20. public std::list<foreign_many_tuple_t>
  21. { };
  22. struct data_extractor_t
  23. {
  24. const table_t& _table;
  25. const read_context& _context;
  26. const ::cppmariadb::row& _row;
  27. foreign_many_list_t& _foreign_many_list;
  28. const filter_t& _filter;
  29. mutable size_t _index;
  30. data_extractor_t(
  31. const table_t& p_table,
  32. const read_context& p_context,
  33. const ::cppmariadb::row& p_row,
  34. foreign_many_list_t& p_foreign_many_list)
  35. : _table (p_table)
  36. , _context (p_context)
  37. , _row (p_row)
  38. , _foreign_many_list(p_foreign_many_list)
  39. , _filter (p_context.filter)
  40. , _index (0)
  41. { }
  42. inline bool has_value() const
  43. { return !_row.at(_index).is_null(); }
  44. inline value_t get_value() const
  45. {
  46. value_t ret;
  47. auto f = _row.at(_index);
  48. if (!f.is_null())
  49. ret = f.get<std::string>();
  50. return ret;
  51. }
  52. inline void next_field() const
  53. { ++_index; }
  54. inline void read_field(const field_t& field, const read_context& context, bool skip = false) const
  55. {
  56. auto value = get_value();
  57. ++_index;
  58. if (!skip)
  59. field.set(context, value);
  60. }
  61. inline bool read_table(const table_t& table, const read_context& context, bool read_base, bool read_derived, bool skip = false) const
  62. {
  63. /* read the base table */
  64. if (read_base && table.base_table)
  65. {
  66. skip = read_table(*table.base_table, context, true, false, skip);
  67. }
  68. /* create a dynamic dataset depending on the derived table */
  69. else if ( read_base
  70. && context.is_dynamic
  71. && !table.derived_tables.empty())
  72. {
  73. auto value = get_value();
  74. next_field();
  75. if (static_cast<bool>(value) && !skip)
  76. {
  77. auto type = utl::from_string<uint>(*value);
  78. auto derived = _table.get_derived_by_table_id(type);
  79. if (!derived)
  80. throw misc::hibernate_exception(std::string("unable to find dereived table for id ") + std::to_string(type));
  81. derived->emplace(context);
  82. }
  83. else
  84. {
  85. skip = true;
  86. }
  87. }
  88. /* create a static dataset */
  89. else if (has_value() && !skip)
  90. {
  91. if (read_base)
  92. {
  93. context.emplace();
  94. }
  95. }
  96. /* no data -> skip */
  97. else
  98. {
  99. skip = true;
  100. }
  101. if (_context.filter.is_excluded(table))
  102. return skip;
  103. /* primary key */
  104. assert(table.primary_key_field);
  105. read_field(*table.primary_key_field, context, skip);
  106. /* data fields */
  107. for (auto& ptr : table.data_fields)
  108. {
  109. assert(ptr);
  110. auto& field = *ptr;
  111. if (!_context.filter.is_excluded(field))
  112. read_field(field, context, skip);
  113. }
  114. /* foreign table one */
  115. for (auto& ptr : table.foreign_table_one_fields)
  116. {
  117. assert(ptr);
  118. assert(ptr->referenced_table);
  119. auto& field = *ptr;
  120. auto& ref_table = *field.referenced_table;
  121. if ( _filter.is_excluded(field)
  122. || _filter.is_excluded(ref_table))
  123. continue;
  124. auto next_context = field.foreign_read(context, skip);
  125. assert(static_cast<bool>(next_context));
  126. read_table(ref_table, *next_context, true, true, skip);
  127. next_context->finish();
  128. }
  129. /* foreign table many */
  130. if (!skip)
  131. {
  132. for (auto& ptr : table.foreign_table_many_fields)
  133. {
  134. assert(ptr);
  135. assert(ptr->referenced_table);
  136. auto& field = *ptr;
  137. auto& ref_table = *field.referenced_table;
  138. if ( _filter.is_excluded(field)
  139. || _filter.is_excluded(ref_table))
  140. continue;
  141. _foreign_many_list.emplace_back(
  142. foreign_many_tuple_t {
  143. field,
  144. field.foreign_read(context, false),
  145. *table.primary_key_field->get(context),
  146. });
  147. }
  148. }
  149. /* derived tables */
  150. if (read_derived && context.is_dynamic)
  151. {
  152. for (auto& ptr : table.derived_tables)
  153. {
  154. assert(ptr);
  155. auto& derived_table = *ptr;
  156. read_table(derived_table, context, false, true, skip);
  157. }
  158. }
  159. return skip;
  160. }
  161. inline void operator()() const
  162. {
  163. _index = 0;
  164. read_table(_table, _context, true, true, false);
  165. if (_index != _row.size())
  166. throw misc::hibernate_exception("result was not completely read!");
  167. }
  168. };
  169. /* select_query_builder_t */
  170. struct select_query_builder_t
  171. {
  172. struct local_context
  173. {
  174. const table_t& table;
  175. std::string alias;
  176. bool add_base;
  177. bool add_derived;
  178. bool is_dynamic;
  179. };
  180. const table_t& _table;
  181. const filter_t& _filter;
  182. bool _is_dynamic;
  183. size_t alias_id { 0 };
  184. size_t index { 0 };
  185. std::ostringstream os;
  186. std::list<std::string> joins;
  187. select_query_builder_t(
  188. const table_t& p_table,
  189. const filter_t& p_filter,
  190. bool p_is_dynamic)
  191. : _table (p_table)
  192. , _filter (p_filter)
  193. , _is_dynamic(p_is_dynamic)
  194. { }
  195. inline std::string make_alias()
  196. { return std::string("T") + std::to_string(alias_id++); }
  197. inline void add_field(const field_t& field, const std::string& alias)
  198. {
  199. if (index++) os << ", ";
  200. os << field.convert_from_open
  201. << "`"
  202. << alias
  203. << "`.`"
  204. << field.field_name
  205. << "`"
  206. << field.convert_from_close;
  207. }
  208. inline bool add_table(const local_context& ctx)
  209. {
  210. bool ret = false;
  211. auto has_alias = !ctx.alias.empty();
  212. auto real_alias = has_alias ? ctx.alias : ctx.table.table_name;
  213. if (ctx.table.base_table && ctx.add_base)
  214. {
  215. assert(ctx.table.base_table->primary_key_field);
  216. auto& base_table = *ctx.table.base_table;
  217. auto& base_key = *base_table.primary_key_field;
  218. auto base_alias = has_alias ? make_alias() : std::string();
  219. auto real_base_alias = has_alias ? base_alias : base_table.table_name;
  220. std::ostringstream ss;
  221. ss << " JOIN `"
  222. << base_table.table_name;
  223. if (has_alias)
  224. {
  225. ss << "` AS `"
  226. << base_alias;
  227. }
  228. ss << "` ON `"
  229. << real_alias
  230. << "`.`"
  231. << base_key.field_name
  232. << "`=`"
  233. << real_base_alias
  234. << "`.`"
  235. << base_key.field_name
  236. << "`";
  237. auto it = joins.insert(joins.end(), ss.str());
  238. if (add_table({
  239. base_table,
  240. base_alias,
  241. true,
  242. false,
  243. ctx.is_dynamic
  244. }))
  245. {
  246. ret = true;
  247. }
  248. else
  249. {
  250. joins.erase(it);
  251. }
  252. }
  253. /* __type */
  254. if ( ctx.is_dynamic
  255. && !ctx.table.base_table
  256. && !ctx.table.derived_tables.empty())
  257. {
  258. if (index++) os << ", ";
  259. os << "`"
  260. << ctx.table.table_name
  261. << "`.`__type` AS `__type`";
  262. ret = true;
  263. }
  264. if (_filter.is_excluded(ctx.table))
  265. return ret;
  266. /* primary key */
  267. assert(ctx.table.primary_key_field);
  268. add_field(*ctx.table.primary_key_field, real_alias);
  269. ret = true;
  270. /* data fields */
  271. for (auto& ptr : ctx.table.data_fields)
  272. {
  273. assert(ptr);
  274. auto& field = *ptr;
  275. if (!_filter.is_excluded(field))
  276. {
  277. add_field(field, real_alias);
  278. }
  279. }
  280. /* foreign table one */
  281. for (auto& ptr : ctx.table.foreign_table_one_fields)
  282. {
  283. assert(ptr);
  284. assert(ptr->table);
  285. assert(ptr->table->primary_key_field);
  286. assert(ptr->referenced_table);
  287. assert(ptr->referenced_table->primary_key_field);
  288. auto& field = *ptr;
  289. auto& table = *field.table;
  290. auto& own_key = *table.primary_key_field;
  291. auto& ref_table = *field.referenced_table;
  292. auto& ref_key = *ref_table.primary_key_field;
  293. if ( _filter.is_excluded(field)
  294. || _filter.is_excluded(ref_table))
  295. continue;
  296. auto new_alias = make_alias();
  297. std::ostringstream ss;
  298. if (ref_table.is_used_in_container)
  299. {
  300. ss << " LEFT JOIN `"
  301. << ref_table.table_name
  302. << "` AS `"
  303. << new_alias
  304. << "` ON `"
  305. << real_alias
  306. << "`.`"
  307. << own_key.field_name
  308. << "`=`"
  309. << new_alias
  310. << "`.`"
  311. << table.table_name
  312. << "_id_"
  313. << field.field_name
  314. << "`";
  315. }
  316. else
  317. {
  318. ss << " LEFT JOIN `"
  319. << ref_table.table_name
  320. << "` AS `"
  321. << new_alias
  322. << "` ON `"
  323. << real_alias
  324. << "`.`"
  325. << ref_key.table_name
  326. << "_id_"
  327. << field.field_name
  328. << "`=`"
  329. << new_alias
  330. << "`.`"
  331. << ref_key.field_name
  332. << "`";
  333. }
  334. auto it = joins.insert(joins.end(), ss.str());
  335. if (!add_table({
  336. ref_table,
  337. new_alias,
  338. true,
  339. true,
  340. field.value_is_pointer
  341. }))
  342. {
  343. joins.erase(it);
  344. }
  345. }
  346. /* derived tables */
  347. if (ctx.add_derived && ctx.is_dynamic)
  348. {
  349. for (auto& ptr : ctx.table.derived_tables)
  350. {
  351. assert(ptr);
  352. assert(ptr->primary_key_field);
  353. auto& derived_table = *ptr;
  354. auto& primary_key = *ctx.table.primary_key_field;
  355. auto derived_alias = has_alias ? make_alias() : std::string();
  356. auto real_derived_alias = has_alias ? derived_alias : derived_table.table_name;
  357. std::ostringstream ss;
  358. ss << " LEFT JOIN `"
  359. << derived_table.table_name;
  360. if (has_alias)
  361. {
  362. ss << "` AS `"
  363. << derived_alias;
  364. }
  365. ss << "` ON `"
  366. << real_alias
  367. << "`.`"
  368. << primary_key.field_name
  369. << "`=`"
  370. << real_derived_alias
  371. << "`.`"
  372. << primary_key.field_name
  373. << "`";
  374. auto it = joins.insert(joins.end(), ss.str());
  375. if (!add_table({
  376. derived_table,
  377. derived_alias,
  378. false,
  379. true,
  380. ctx.is_dynamic,
  381. }))
  382. {
  383. joins.erase(it);
  384. }
  385. }
  386. }
  387. return ret;
  388. }
  389. inline std::string operator()()
  390. {
  391. os << "SELECT ";
  392. add_table({
  393. _table,
  394. "",
  395. true,
  396. true,
  397. _is_dynamic,
  398. });
  399. os << " FROM `"
  400. << _table.table_name
  401. << "`";
  402. for (auto& join : joins)
  403. os << join;
  404. os << " ?where! ?order! ?limit!";
  405. return os.str();
  406. }
  407. };
  408. /* delete_query_builder_t */
  409. struct delete_query_builder_t
  410. {
  411. const table_t& _table;
  412. size_t alias_id { 0 };
  413. std::ostringstream os;
  414. std::list<std::string> names;
  415. delete_query_builder_t(
  416. const table_t& p_table)
  417. : _table (p_table)
  418. { }
  419. inline std::string make_alias()
  420. { return std::string("T") + std::to_string(alias_id++); }
  421. inline void add_table(const table_t& table, const std::string& alias, bool add_base, bool add_derived)
  422. {
  423. auto has_alias = !alias.empty();
  424. auto real_alias = has_alias ? alias : table.table_name;
  425. if (table.base_table && add_base)
  426. {
  427. assert(table.base_table->primary_key_field);
  428. auto& base_table = *table.base_table;
  429. auto& base_key = *base_table.primary_key_field;
  430. auto base_alias = has_alias ? make_alias() : std::string();
  431. auto real_base_alias = has_alias ? base_alias : base_table.table_name;
  432. os << " LEFT JOIN `"
  433. << base_table.table_name;
  434. if (has_alias)
  435. {
  436. os << "` AS `"
  437. << base_alias;
  438. }
  439. os << "` ON `"
  440. << real_alias
  441. << "`.`"
  442. << base_key.field_name
  443. << "`=`"
  444. << real_base_alias
  445. << "`.`"
  446. << base_key.field_name
  447. << "`";
  448. add_table(base_table, base_alias, true, false);
  449. }
  450. names.emplace_back(real_alias);
  451. /* foreign table one */
  452. for (auto& ptr : table.foreign_table_one_fields)
  453. {
  454. assert(ptr);
  455. assert(ptr->table);
  456. assert(ptr->table->primary_key_field);
  457. assert(ptr->referenced_table);
  458. assert(ptr->referenced_table->primary_key_field);
  459. auto& field = *ptr;
  460. auto& own_key = *table.primary_key_field;
  461. auto& ref_table = *field.referenced_table;
  462. auto& ref_key = *ref_table.primary_key_field;
  463. auto new_alias = make_alias();
  464. if (ref_table.is_used_in_container)
  465. {
  466. os << " LEFT JOIN `"
  467. << ref_table.table_name
  468. << "` AS `"
  469. << new_alias
  470. << "` ON `"
  471. << real_alias
  472. << "`.`"
  473. << own_key.field_name
  474. << "`=`"
  475. << new_alias
  476. << "`.`"
  477. << table.table_name
  478. << "_id_"
  479. << field.field_name
  480. << "`";
  481. }
  482. else
  483. {
  484. os << " LEFT JOIN `"
  485. << ref_table.table_name
  486. << "` AS `"
  487. << new_alias
  488. << "` ON `"
  489. << real_alias
  490. << "`.`"
  491. << ref_key.table_name
  492. << "_id_"
  493. << field.field_name
  494. << "`=`"
  495. << new_alias
  496. << "`.`"
  497. << ref_key.field_name
  498. << "`";
  499. }
  500. add_table(ref_table, new_alias, true, true);
  501. }
  502. /* derived tables */
  503. if (add_derived)
  504. {
  505. for (auto& ptr : table.derived_tables)
  506. {
  507. assert(ptr);
  508. assert(ptr->primary_key_field);
  509. auto& derived_table = *ptr;
  510. auto& primary_key = *table.primary_key_field;
  511. auto derived_alias = has_alias ? make_alias() : std::string();
  512. auto real_derived_alias = has_alias ? derived_alias : derived_table.table_name;
  513. os << " LEFT JOIN `"
  514. << derived_table.table_name;
  515. if (has_alias)
  516. {
  517. os << "` AS `"
  518. << derived_alias;
  519. }
  520. os << "` ON `"
  521. << real_alias
  522. << "`.`"
  523. << primary_key.field_name
  524. << "`=`"
  525. << real_derived_alias
  526. << "`.`"
  527. << primary_key.field_name
  528. << "`";
  529. add_table(derived_table, derived_alias, false, true);
  530. }
  531. }
  532. }
  533. inline std::string operator()(const std::string* where)
  534. {
  535. os << " FROM `"
  536. << _table.table_name
  537. << "`";
  538. add_table(_table, "", true, true);
  539. if (where)
  540. {
  541. os << " " << *where;
  542. }
  543. else
  544. {
  545. os << " ?where!";
  546. }
  547. std::ostringstream ss;
  548. ss << "DELETE ";
  549. bool first = true;
  550. for (auto& name : names)
  551. {
  552. if (first)
  553. first = false;
  554. else
  555. ss << ", ";
  556. ss << "`"
  557. << name
  558. << "`";
  559. }
  560. ss << os.str();
  561. return ss.str();
  562. }
  563. };
  564. /* build queries */
  565. std::string build_init_stage1_query(const table_t& table)
  566. {
  567. std::ostringstream os;
  568. /* CREATE TABLE */
  569. os << "CREATE TABLE IF NOT EXISTS `"
  570. << table.table_name
  571. << "`"
  572. << indent
  573. << "("
  574. << incindent;
  575. /* primary key */
  576. {
  577. assert(table.primary_key_field);
  578. auto& key_info = *table.primary_key_field;
  579. auto args = key_info.create_arguments;
  580. os << indent
  581. << "`"
  582. << key_info.field_name
  583. << "` "
  584. << key_info.type
  585. << " NOT NULL"
  586. << (args.empty() ? "" : " ")
  587. << args
  588. << ",";
  589. }
  590. /* base table key fields */
  591. if (static_cast<bool>(table.base_table))
  592. {
  593. auto& base_table_info = *table.base_table;
  594. assert(base_table_info.primary_key_field);
  595. auto& key_info = *base_table_info.primary_key_field;
  596. os << indent
  597. << "`"
  598. << key_info.field_name
  599. << "` "
  600. << key_info.type
  601. << " NOT NULL,";
  602. }
  603. /* foreign table one fields */
  604. for (auto& ptr : table.foreign_table_one_fields)
  605. {
  606. assert(static_cast<bool>(ptr));
  607. auto& field_info = *ptr;
  608. assert(field_info.referenced_table);
  609. assert(field_info.referenced_table->primary_key_field);
  610. if (field_info.referenced_table->is_used_in_container)
  611. continue;
  612. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  613. os << indent
  614. << "`"
  615. << ref_key_info.table_name
  616. << "_id_"
  617. << field_info.field_name
  618. << "` "
  619. << ref_key_info.type
  620. << (field_info.value_is_nullable
  621. ? " NULL DEFAULT NULL,"
  622. : " NOT NULL,");
  623. }
  624. /* foreign fields */
  625. for (auto& ptr : table.foreign_key_fields)
  626. {
  627. assert(static_cast<bool>(ptr));
  628. auto& field_info = *ptr;
  629. assert(field_info.table);
  630. assert(field_info.table->primary_key_field);
  631. auto& ref_key_info = *field_info.table->primary_key_field;
  632. os << indent
  633. << "`"
  634. << field_info.table_name
  635. << "_id_"
  636. << field_info.field_name
  637. << "` "
  638. << ref_key_info.type
  639. << " NULL DEFAULT NULL,";
  640. if (field_info.value_is_ordered)
  641. {
  642. os << indent
  643. << "`"
  644. << field_info.table_name
  645. << "_index_"
  646. << field_info.field_name
  647. << "` INT UNSIGNED NOT NULL,";
  648. }
  649. }
  650. /* data fields */
  651. for (auto& ptr : table.data_fields)
  652. {
  653. assert(static_cast<bool>(ptr));
  654. auto& field_info = *ptr;
  655. os << indent
  656. << "`"
  657. << field_info.field_name
  658. << "` "
  659. << field_info.type
  660. << (field_info.value_is_nullable
  661. ? " NULL DEFAULT NULL,"
  662. : " NOT NULL,");
  663. }
  664. /* type field for derived tables */
  665. if (!table.derived_tables.empty() &&
  666. !table.base_table)
  667. {
  668. os << indent
  669. << "`__type` INT UNSIGNED NOT NULL,";
  670. }
  671. /* PRIMARY KEY */
  672. {
  673. assert(table.primary_key_field);
  674. auto& key_info = *table.primary_key_field;
  675. os << indent
  676. << "PRIMARY KEY ( `"
  677. << key_info.field_name
  678. << "` )";
  679. }
  680. /* UNIQUE INDEX primary key */
  681. {
  682. assert(table.primary_key_field);
  683. auto& key_info = *table.primary_key_field;
  684. os << ','
  685. << indent
  686. << "UNIQUE INDEX `index_"
  687. << key_info.field_name
  688. << "` ( `"
  689. << key_info.field_name
  690. << "` ASC )";
  691. }
  692. /* UNIQUE INDEX base table keys */
  693. if (table.base_table)
  694. {
  695. auto& table_info = *table.base_table;
  696. assert(table_info.primary_key_field);
  697. auto& key_info = *table_info.primary_key_field;
  698. os << ','
  699. << indent
  700. << "UNIQUE INDEX `index_"
  701. << key_info.field_name
  702. << "` ( `"
  703. << key_info.field_name
  704. << "` ASC )";
  705. }
  706. /* INDEX foreign table one fields */
  707. for (auto& ptr : table.foreign_table_one_fields)
  708. {
  709. assert(static_cast<bool>(ptr));
  710. auto& field_info = *ptr;
  711. assert(field_info.referenced_table);
  712. assert(field_info.referenced_table->primary_key_field);
  713. if (field_info.referenced_table->is_used_in_container)
  714. continue;
  715. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  716. os << ","
  717. << indent
  718. << "INDEX `index_"
  719. << ref_key_info.table_name
  720. << "_id_"
  721. << field_info.field_name
  722. << "` ( `"
  723. << ref_key_info.table_name
  724. << "_id_"
  725. << field_info.field_name
  726. << "` ASC )";
  727. }
  728. /* INDEX foreign fields */
  729. for (auto& ptr : table.foreign_key_fields)
  730. {
  731. assert(static_cast<bool>(ptr));
  732. auto& field_info = *ptr;
  733. os << ","
  734. << indent
  735. << "INDEX `index_"
  736. << field_info.table_name
  737. << "_id_"
  738. << field_info.field_name
  739. << "` ( `"
  740. << field_info.table_name
  741. << "_id_"
  742. << field_info.field_name
  743. << "` ASC )";
  744. }
  745. /* CREATE TABLE end */
  746. os << decindent
  747. << indent
  748. << ")"
  749. << indent
  750. << "ENGINE = InnoDB"
  751. << indent
  752. << "DEFAULT CHARACTER SET = utf8";
  753. return os.str();
  754. }
  755. std::string build_init_stage2_query(const table_t& table)
  756. {
  757. std::ostringstream os;
  758. /* ALTER TABLE */
  759. os << "ALTER TABLE `"
  760. << table.table_name
  761. << "`"
  762. << incindent;
  763. size_t index = 0;
  764. /* CONSTRAINT base table */
  765. if (table.base_table)
  766. {
  767. assert(table.base_table->primary_key_field);
  768. auto& ref_key_info = *table.base_table->primary_key_field;
  769. if (index++) os << ",";
  770. os << indent
  771. << "ADD CONSTRAINT `fk_"
  772. << table.table_name
  773. << "_"
  774. << ref_key_info.field_name
  775. << "`"
  776. << incindent
  777. << indent
  778. << "FOREIGN KEY IF NOT EXISTS (`"
  779. << ref_key_info.field_name
  780. << "`)"
  781. << indent
  782. << "REFERENCES `"
  783. << ref_key_info.schema_name
  784. << "`.`"
  785. << ref_key_info.table_name
  786. << "` (`"
  787. << ref_key_info.field_name
  788. << "`)"
  789. << indent
  790. << "ON DELETE CASCADE"
  791. << indent
  792. << "ON UPDATE CASCADE"
  793. << decindent;
  794. }
  795. /* CONSTRAINT foreign table one fields */
  796. for (auto& ptr : table.foreign_table_one_fields)
  797. {
  798. assert(static_cast<bool>(ptr));
  799. auto& field_info = *ptr;
  800. assert(field_info.referenced_table);
  801. assert(field_info.referenced_table->primary_key_field);
  802. if (field_info.referenced_table->is_used_in_container)
  803. continue;
  804. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  805. if (index++) os << ",";
  806. os << indent
  807. << "ADD CONSTRAINT `fk_"
  808. << table.table_name
  809. << "_"
  810. << ref_key_info.table_name
  811. << "_"
  812. << field_info.field_name
  813. << "`"
  814. << incindent
  815. << indent
  816. << "FOREIGN KEY IF NOT EXISTS (`"
  817. << ref_key_info.table_name
  818. << "_id_"
  819. << field_info.field_name
  820. << "`)"
  821. << indent
  822. << "REFERENCES `"
  823. << ref_key_info.schema_name
  824. << "`.`"
  825. << ref_key_info.table_name
  826. << "` (`"
  827. << ref_key_info.field_name
  828. << "`)"
  829. << indent;
  830. if (field_info.value_is_nullable)
  831. os << "ON DELETE SET NULL";
  832. else
  833. os << "ON DELETE CASCADE";
  834. os << indent
  835. << "ON UPDATE NO ACTION"
  836. << decindent;
  837. }
  838. /* CONSTRAINT foreign fields */
  839. for (auto& ptr : table.foreign_key_fields)
  840. {
  841. assert(static_cast<bool>(ptr));
  842. auto& field_info = *ptr;
  843. assert(field_info.table);
  844. assert(field_info.table->primary_key_field);
  845. auto& ref_key_info = *field_info.table->primary_key_field;
  846. if (index++) os << ",";
  847. os << indent
  848. << "ADD CONSTRAINT `fk_"
  849. << table.table_name
  850. << "_"
  851. << field_info.table_name
  852. << "_"
  853. << field_info.field_name
  854. << "`"
  855. << incindent
  856. << indent
  857. << "FOREIGN KEY IF NOT EXISTS (`"
  858. << field_info.table_name
  859. << "_id_"
  860. << field_info.field_name
  861. << "`)"
  862. << indent
  863. << "REFERENCES `"
  864. << ref_key_info.schema_name
  865. << "`.`"
  866. << ref_key_info.table_name
  867. << "` (`"
  868. << ref_key_info.field_name
  869. << "`)"
  870. << indent
  871. << "ON DELETE SET NULL"
  872. << indent
  873. << "ON UPDATE NO ACTION"
  874. << decindent;
  875. }
  876. return index == 0
  877. ? std::string { }
  878. : os.str();
  879. }
  880. std::string build_create_update_query(const table_t& table, const filter_t* filter, const field_t* owner)
  881. {
  882. std::ostringstream os;
  883. size_t index = 0;
  884. bool is_update = static_cast<bool>(filter);
  885. /* INSER INTO / UPDATE */
  886. os << (is_update
  887. ? "UPDATE"
  888. : "INSERT INTO")
  889. << " `"
  890. << table.table_name
  891. << "`";
  892. /* primary key */
  893. if (!is_update)
  894. {
  895. assert(table.primary_key_field);
  896. auto& key_info = *table.primary_key_field;
  897. if (!key_info.value_is_auto_incremented)
  898. {
  899. if (index++)
  900. os << ", ";
  901. else
  902. os << " SET ";
  903. os << "`"
  904. << key_info.field_name
  905. << "`="
  906. << key_info.convert_to_open
  907. << "?"
  908. << key_info.field_name
  909. << "?"
  910. << key_info.convert_to_close;
  911. }
  912. }
  913. /* base table key fields */
  914. if ( static_cast<bool>(table.base_table)
  915. && ( !is_update
  916. || !filter->is_excluded(*table.base_table)))
  917. {
  918. if (index++)
  919. os << ", ";
  920. else
  921. os << " SET ";
  922. auto& base_table_info = *table.base_table;
  923. assert(base_table_info.primary_key_field);
  924. auto& key_info = *base_table_info.primary_key_field;
  925. os << "`"
  926. << key_info.field_name
  927. << "`="
  928. << key_info.convert_to_open
  929. << "?"
  930. << key_info.field_name
  931. << "?"
  932. << key_info.convert_to_close;
  933. }
  934. /* foreign table one fields */
  935. for (auto& ptr : table.foreign_table_one_fields)
  936. {
  937. assert(static_cast<bool>(ptr));
  938. auto& field_info = *ptr;
  939. if (is_update && filter->is_excluded(field_info))
  940. continue;
  941. assert(field_info.referenced_table);
  942. assert(field_info.referenced_table->primary_key_field);
  943. if (field_info.referenced_table->is_used_in_container)
  944. continue;
  945. if (index++)
  946. os << ", ";
  947. else
  948. os << " SET ";
  949. auto& key_info = *field_info.referenced_table->primary_key_field;
  950. os << "`"
  951. << key_info.table_name
  952. << "_id_"
  953. << field_info.field_name
  954. << "`="
  955. << key_info.convert_to_open
  956. << "?"
  957. << key_info.table_name
  958. << "_id_"
  959. << field_info.field_name
  960. << "?"
  961. << key_info.convert_to_close;
  962. }
  963. /* foreign fields */
  964. for (auto& ptr : table.foreign_key_fields)
  965. {
  966. assert(static_cast<bool>(ptr));
  967. if (is_update && ptr != owner)
  968. continue;
  969. if (index++)
  970. os << ", ";
  971. else
  972. os << " SET ";
  973. auto& field_info = *ptr;
  974. assert(field_info.table);
  975. assert(field_info.table->primary_key_field);
  976. auto& key_info = *field_info.table->primary_key_field;
  977. os << "`"
  978. << field_info.table_name
  979. << "_id_"
  980. << field_info.field_name
  981. << "`="
  982. << key_info.convert_to_open
  983. << "?"
  984. << field_info.table_name
  985. << "_id_"
  986. << field_info.field_name
  987. << "?"
  988. << key_info.convert_to_close;
  989. if (field_info.value_is_ordered)
  990. {
  991. if (index++)
  992. os << ", ";
  993. else
  994. os << " SET ";
  995. os << "`"
  996. << field_info.table_name
  997. << "_index_"
  998. << field_info.field_name
  999. << "`=?\?";
  1000. }
  1001. }
  1002. /* data fields */
  1003. for (auto& ptr : table.data_fields)
  1004. {
  1005. assert(ptr);
  1006. auto& field_info = *ptr;
  1007. if (is_update && filter->is_excluded(field_info))
  1008. continue;
  1009. if (index++)
  1010. os << ", ";
  1011. else
  1012. os << " SET ";
  1013. os << "`"
  1014. << field_info.field_name
  1015. << "`="
  1016. << field_info.convert_to_open
  1017. << "?"
  1018. << field_info.field_name
  1019. << "?"
  1020. << field_info.convert_to_close;
  1021. }
  1022. /* type field for derived tables */
  1023. if ( !table.derived_tables.empty()
  1024. && !table.base_table
  1025. && !is_update)
  1026. {
  1027. if (index++)
  1028. os << ", ";
  1029. else
  1030. os << " SET ";
  1031. os << "`__type`=?__type?";
  1032. }
  1033. /* where primary key (for update) */
  1034. if (is_update)
  1035. {
  1036. assert(table.primary_key_field);
  1037. auto& key_info = *table.primary_key_field;
  1038. os << " WHERE `"
  1039. << key_info.field_name
  1040. << "`="
  1041. << key_info.convert_to_open
  1042. << "?"
  1043. << key_info.field_name
  1044. << "?"
  1045. << key_info.convert_to_close;
  1046. }
  1047. return index == 0 && !(table.primary_key_field->value_is_auto_incremented && !is_update)
  1048. ? std::string()
  1049. : os.str();
  1050. }
  1051. std::string build_select_query(
  1052. const table_t& table,
  1053. const filter_t& filter,
  1054. bool is_dynamic)
  1055. {
  1056. return select_query_builder_t(table, filter, is_dynamic)();
  1057. }
  1058. /* execute_create_update */
  1059. std::string table_t::execute_create_update(
  1060. const create_update_context& context,
  1061. ::cppmariadb::statement* statement) const
  1062. {
  1063. auto& connection = context.connection;
  1064. auto& filter = context.filter;
  1065. size_t index = 0;
  1066. bool is_update = context.is_update;
  1067. std::string primary_key;
  1068. if (statement) statement->clear();
  1069. /* primary key */
  1070. assert(primary_key_field);
  1071. if (is_update)
  1072. {
  1073. primary_key = get_primary_key(context);
  1074. }
  1075. else if (!primary_key_field->value_is_auto_incremented)
  1076. {
  1077. primary_key = primary_key_field->generate_value(context.connection);
  1078. if (statement) statement->set(index, primary_key);
  1079. ++index;
  1080. }
  1081. /* base_key */
  1082. if ( base_table
  1083. && ( !is_update
  1084. || !filter.is_excluded(*base_table)))
  1085. {
  1086. auto new_context = context;
  1087. if (!new_context.derived_table)
  1088. new_context.derived_table = this;
  1089. std::string key = create_update_base(new_context);
  1090. if (statement) statement->set(index, std::move(key));
  1091. ++index;
  1092. }
  1093. if (is_update && filter.is_excluded(*this))
  1094. return primary_key;
  1095. /* foreign table one fields */
  1096. for (auto& ptr : foreign_table_one_fields)
  1097. {
  1098. assert(ptr);
  1099. assert(ptr->referenced_table);
  1100. auto& field = *ptr;
  1101. if (is_update && filter.is_excluded(field))
  1102. continue;
  1103. if (field.referenced_table->is_used_in_container)
  1104. continue;
  1105. /* insert/update dataset */
  1106. value_t key = field.foreign_create_update(context);
  1107. if (key.has_value())
  1108. {
  1109. if (statement) statement->set(index, std::move(key));
  1110. }
  1111. else if (field.value_is_nullable)
  1112. {
  1113. if (statement) statement->set_null(index);
  1114. }
  1115. else
  1116. {
  1117. throw misc::hibernate_exception("Received null key for non nullable foreign dataset!");
  1118. }
  1119. ++index;
  1120. /* cleanup old dataset (if new one was created) */
  1121. if (context.is_update)
  1122. {
  1123. auto& delete_statement = field.get_statement_foreign_one_delete(key.has_value());
  1124. delete_statement.set(0, primary_key);
  1125. if (key.has_value())
  1126. delete_statement.set(1, *key);
  1127. cpphibernate_debug_log("execute DELETE old foreign one query: " << delete_statement.query(connection));
  1128. connection.execute(delete_statement);
  1129. table_set processed;
  1130. field.referenced_table->destroy_cleanup(context, processed, true, true);
  1131. }
  1132. }
  1133. /* foreign fields */
  1134. for (auto& ptr : foreign_key_fields)
  1135. {
  1136. assert(ptr);
  1137. if (is_update && ptr != context.owner_field)
  1138. continue;
  1139. auto& field_info = *ptr;
  1140. bool set_value =
  1141. context.owner_field
  1142. && ptr == context.owner_field;
  1143. if (set_value)
  1144. {
  1145. assert(!context.owner_key.empty());
  1146. if (statement) statement->set(index, context.owner_key);
  1147. }
  1148. else
  1149. {
  1150. if (statement) statement->set_null(index);
  1151. }
  1152. ++index;
  1153. if (field_info.value_is_ordered)
  1154. {
  1155. if (set_value)
  1156. {
  1157. if (statement) statement->set(index, context.index);
  1158. }
  1159. else
  1160. {
  1161. if (statement) statement->set(index, 0);
  1162. }
  1163. ++index;
  1164. }
  1165. }
  1166. /* data fields */
  1167. for (auto& ptr : data_fields)
  1168. {
  1169. assert(ptr);
  1170. if (is_update && filter.is_excluded(*ptr))
  1171. continue;
  1172. auto& field_info = *ptr;
  1173. auto value = field_info.get(context);
  1174. if (value.has_value())
  1175. {
  1176. if (statement) statement->set(index, *value);
  1177. }
  1178. else
  1179. {
  1180. if (statement) statement->set_null(index);
  1181. }
  1182. ++index;
  1183. }
  1184. /* type field for derived tables */
  1185. if ( !derived_tables.empty()
  1186. && !base_table
  1187. && !is_update)
  1188. {
  1189. if (statement) statement->set(index, context.derived_table
  1190. ? context.derived_table->table_id
  1191. : table_id);
  1192. ++index;
  1193. }
  1194. /* where primary key (for update) */
  1195. if (is_update)
  1196. {
  1197. assert(primary_key_field);
  1198. if (statement) statement->set(index, *primary_key_field->get(context));
  1199. ++index;
  1200. }
  1201. /* execute */
  1202. if (statement)
  1203. {
  1204. if (!is_update)
  1205. {
  1206. cpphibernate_debug_log("execute INSERT query: " << statement->query(connection));
  1207. }
  1208. else
  1209. {
  1210. cpphibernate_debug_log("execute UPDATE query: " << statement->query(connection));
  1211. }
  1212. if ( primary_key_field->value_is_auto_incremented
  1213. && !is_update)
  1214. {
  1215. auto id = connection.execute_id(*statement);
  1216. primary_key = utl::to_string(id);
  1217. }
  1218. else
  1219. {
  1220. auto count = connection.execute_rows(*statement);
  1221. if (count > 1)
  1222. throw misc::hibernate_exception("Expected one/ row to be inserted/updated!");
  1223. cpphibernate_debug_log(count << " rows inserted/updated");
  1224. }
  1225. primary_key_field->set(context, primary_key);
  1226. }
  1227. /* foreign table many fields */
  1228. for (auto& ptr : foreign_table_fields)
  1229. {
  1230. assert(ptr);
  1231. assert(ptr->referenced_table);
  1232. auto& field = *ptr;
  1233. auto& ref_table = *field.referenced_table;
  1234. if (!ref_table.is_used_in_container)
  1235. continue;
  1236. if ( is_update
  1237. && ( filter.is_excluded(field)
  1238. || filter.is_excluded(ref_table)))
  1239. continue;
  1240. /* set foreign keys of existing elements to null */
  1241. if (context.is_update)
  1242. {
  1243. auto& update_statement = field.get_statement_foreign_many_update();
  1244. update_statement.set(0, primary_key);
  1245. cpphibernate_debug_log("execute UPDATE old foreign many query: " << update_statement.query(connection));
  1246. connection.execute(update_statement);
  1247. }
  1248. /* update elements */
  1249. auto next_context = context;
  1250. next_context.owner_field = ptr;
  1251. next_context.owner_key = primary_key;
  1252. next_context.derived_table = nullptr;
  1253. field.foreign_create_update(next_context);
  1254. /* delete non referenced elements */
  1255. if (context.is_update)
  1256. {
  1257. table_set processed;
  1258. ref_table.destroy_cleanup(context, processed, true, true);
  1259. }
  1260. }
  1261. return primary_key;
  1262. }
  1263. /* table_t */
  1264. void table_t::print(std::ostream& os) const
  1265. {
  1266. os << indent << '{'
  1267. << incindent
  1268. << indent << "\"dataset_id\": " << dataset_id << ","
  1269. << indent << "\"base_dataset_id\": " << base_dataset_id << ","
  1270. << indent << "\"table_id\": " << table_id << ","
  1271. << indent << "\"derived_dataset_ids\": " << misc::print_container(derived_dataset_ids, false) << ","
  1272. << indent << "\"schema_name\": \"" << schema_name << "\","
  1273. << indent << "\"table_name\": \"" << table_name << "\","
  1274. << indent << "\"fields\":" << misc::print_container(fields, true, [](auto& s, auto& field) {
  1275. field->print(s);
  1276. }) << ","
  1277. << indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->table_name + "\"" : "null") << ","
  1278. << indent << "\"derived_tables\":" << misc::print_container(derived_tables, true, [](auto& s, auto& ptr){
  1279. s << indent << '"' << ptr->table_name << '"';
  1280. }) << ","
  1281. << indent << "\"primary_key_field\": " << (primary_key_field ? std::string("\"") + primary_key_field->field_name + "\"" : "null") << ","
  1282. << indent << "\"foreign_key_fields\": " << misc::print_container(foreign_key_fields, true, [](auto& s, auto& ptr){
  1283. s << indent << '"' << ptr->table_name << '.' << ptr->field_name << '"';
  1284. }) << ","
  1285. << indent << "\"foreign_table_fields\": " << misc::print_container(foreign_table_fields, true, [](auto& s, auto& ptr){
  1286. s << indent << '"' << ptr->field_name << '"';
  1287. }) << ","
  1288. << indent << "\"foreign_table_one_fields\": " << misc::print_container(foreign_table_one_fields, true, [](auto& s, auto& ptr){
  1289. s << indent << '"' << ptr->field_name << '"';
  1290. }) << ","
  1291. << indent << "\"foreign_table_many_fields\": " << misc::print_container(foreign_table_many_fields, true, [](auto& s, auto& ptr){
  1292. s << indent << '"' << ptr->field_name << '"';
  1293. }) << ","
  1294. << indent << "\"data_fields\": " << misc::print_container(data_fields, true, [](auto& s, auto& ptr){
  1295. s << indent << '"' << ptr->field_name << '"';
  1296. })
  1297. << decindent
  1298. << indent << '}';
  1299. }
  1300. const table_t* table_t::get_derived_by_table_id(size_t id) const
  1301. {
  1302. if (table_id == id)
  1303. return this;
  1304. for (auto ptr : derived_tables)
  1305. {
  1306. assert(ptr);
  1307. auto ret = ptr->get_derived_by_table_id(id);
  1308. if (ret) return ret;
  1309. }
  1310. return nullptr;
  1311. }
  1312. const table_t* table_t::get_derived_by_dataset_id(size_t id) const
  1313. {
  1314. if (dataset_id == id)
  1315. return this;
  1316. for (auto ptr : derived_tables)
  1317. {
  1318. assert(ptr);
  1319. auto ret = ptr->get_derived_by_dataset_id(id);
  1320. if (ret) return ret;
  1321. }
  1322. return nullptr;
  1323. }
  1324. void table_t::emplace(const read_context& context) const
  1325. { throw misc::hibernate_exception(std::string("'") + table_name + "' does not implement the emplace() method!"); }
  1326. std::string table_t::get_where_primary_key(const data_context& context) const
  1327. {
  1328. assert(primary_key_field);
  1329. auto& field = *primary_key_field;
  1330. auto primary_key = *field.get(context);
  1331. std::ostringstream os;
  1332. os << "WHERE `"
  1333. << field.table_name
  1334. << "`.`"
  1335. << field.field_name
  1336. << "`="
  1337. << field.convert_to_open
  1338. << "'"
  1339. << context.connection.escape(primary_key)
  1340. << "'"
  1341. << field.convert_to_close;
  1342. return os.str();
  1343. }
  1344. std::string table_t::build_delete_query(const std::string* where) const
  1345. { return delete_query_builder_t(*this)(where); }
  1346. ::cppmariadb::statement& table_t::get_statement_key_from_base() const
  1347. {
  1348. if (!_statement_key_from_base)
  1349. {
  1350. if (!base_table)
  1351. throw exception(std::string("table has no base table: ") + table_name);
  1352. assert(primary_key_field);
  1353. assert(base_table);
  1354. assert(base_table->primary_key_field);
  1355. auto& key_info = *primary_key_field;
  1356. auto& base_key = *base_table->primary_key_field;
  1357. std::ostringstream os;
  1358. os << "SELECT `"
  1359. << key_info.field_name
  1360. << "` FROM `"
  1361. << key_info.table_name
  1362. << "` WHERE `"
  1363. << base_key.table_name
  1364. << "_id`=?\?";
  1365. _statement_key_from_base.reset(new ::cppmariadb::statement(os.str()));
  1366. }
  1367. return *_statement_key_from_base;
  1368. }
  1369. ::cppmariadb::statement& table_t::get_statement_create_table() const
  1370. {
  1371. if (_statement_create_table)
  1372. return *_statement_create_table;
  1373. auto query = build_init_stage1_query(*this);
  1374. _statement_create_table.reset(new ::cppmariadb::statement(query));
  1375. return *_statement_create_table;
  1376. }
  1377. ::cppmariadb::statement* table_t::get_statement_alter_table() const
  1378. {
  1379. if (!_statement_alter_table)
  1380. {
  1381. auto query = build_init_stage2_query(*this);
  1382. _statement_alter_table.reset(new ::cppmariadb::statement(query));
  1383. }
  1384. return _statement_alter_table->empty()
  1385. ? nullptr
  1386. : _statement_alter_table.get();
  1387. }
  1388. ::cppmariadb::statement* table_t::get_statement_insert_into() const
  1389. {
  1390. if (!_statement_insert_into)
  1391. {
  1392. auto query = build_create_update_query(*this, nullptr, nullptr);
  1393. _statement_insert_into.reset(new ::cppmariadb::statement(query));
  1394. }
  1395. return _statement_insert_into->empty()
  1396. ? nullptr
  1397. : _statement_insert_into.get();
  1398. }
  1399. ::cppmariadb::statement& table_t::get_statement_select(const read_context& context) const
  1400. {
  1401. auto& map = context.is_dynamic
  1402. ? _statement_select_dynamic
  1403. : _statement_select_static;
  1404. auto key = std::make_tuple(context.filter.cache_id, static_cast<const field_t*>(nullptr));
  1405. auto it = map.find(key);
  1406. if (it == map.end())
  1407. {
  1408. auto query = build_select_query(*this, context.filter, context.is_dynamic);
  1409. it = map.emplace(key, ::cppmariadb::statement(query)).first;
  1410. }
  1411. return it->second;
  1412. }
  1413. ::cppmariadb::statement* table_t::get_statement_update(const filter_t& filter, const field_t* owner) const
  1414. {
  1415. auto key = std::make_tuple(filter.cache_id, owner);
  1416. auto it = _statement_update.find(key);
  1417. if (it == _statement_update.end())
  1418. {
  1419. auto query = build_create_update_query(*this, &filter, owner);
  1420. it = _statement_update.emplace(key, ::cppmariadb::statement(query)).first;
  1421. }
  1422. return it->second.empty()
  1423. ? nullptr
  1424. : &it->second;
  1425. }
  1426. ::cppmariadb::statement& table_t::get_statement_foreign_many_delete() const
  1427. {
  1428. if (!_statement_foreign_many_delete)
  1429. {
  1430. std::ostringstream os;
  1431. auto first = true;
  1432. os << "WHERE";
  1433. for (auto ptr : foreign_key_fields)
  1434. {
  1435. assert(ptr);
  1436. auto& field = *ptr;
  1437. if (first)
  1438. first = false;
  1439. else
  1440. os << " AND";
  1441. os << " (`"
  1442. << field.table_name
  1443. << "_id_"
  1444. << field.field_name
  1445. << "` IS NULL)";
  1446. }
  1447. std::string where = os.str();
  1448. auto query = delete_query_builder_t(*this)(&where);
  1449. _statement_foreign_many_delete.reset(new ::cppmariadb::statement(query));
  1450. }
  1451. return *_statement_foreign_many_delete;
  1452. }
  1453. ::cppmariadb::statement& table_t::get_statement_delete() const
  1454. {
  1455. if (!_statement_delete)
  1456. {
  1457. auto query = delete_query_builder_t(*this)(nullptr);
  1458. _statement_delete.reset(new ::cppmariadb::statement(query));
  1459. }
  1460. return *_statement_delete;
  1461. }
  1462. void table_t::execute_foreign_many_delete(const base_context& context) const
  1463. {
  1464. if (foreign_key_fields.empty())
  1465. return;
  1466. auto& connection = context.connection;
  1467. auto& statement = get_statement_foreign_many_delete();
  1468. cpphibernate_debug_log("execute DELETE old foreign many query: " << statement.query(connection));
  1469. connection.execute(statement);
  1470. }
  1471. std::string table_t::get_primary_key(const data_context& context) const
  1472. {
  1473. assert(primary_key_field);
  1474. if ( primary_key_field->is_default(context)
  1475. && base_table)
  1476. {
  1477. auto key = get_key_from_base(context);
  1478. primary_key_field->set(context, key);
  1479. return key;
  1480. }
  1481. else
  1482. {
  1483. return *primary_key_field->get(context);
  1484. }
  1485. }
  1486. std::string table_t::get_key_from_base(const data_context& context) const
  1487. {
  1488. if (!base_table)
  1489. {
  1490. throw exception(std::string("table has no base table: ") + table_name);
  1491. }
  1492. auto& statement = get_statement_key_from_base();
  1493. auto base_key = base_table->get_primary_key(context);
  1494. statement.set(0, base_key);
  1495. auto result = context.connection.execute_stored(statement);
  1496. if (!result)
  1497. throw exception("unable to fetch key from database: unable to execute query!");
  1498. auto row = result->next();
  1499. if (!row)
  1500. throw exception("unable to fetch key from database: result set is empty!");
  1501. return row->at(0).get<std::string>();
  1502. }
  1503. std::string table_t::create_update_base(const create_update_context& context) const
  1504. {
  1505. throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
  1506. << "'" << this->table_name << "' does not implement create_update_base!").str());
  1507. }
  1508. void table_t::init_stage1_exec(const init_context& context) const
  1509. {
  1510. auto& statement = get_statement_create_table();
  1511. auto& connection = context.connection;
  1512. cpphibernate_debug_log("execute CREATE TABLE query: " << statement.query(connection));
  1513. connection.execute(statement);
  1514. }
  1515. void table_t::init_stage2_exec(const init_context& context) const
  1516. {
  1517. auto* statement = get_statement_alter_table();
  1518. auto& connection = context.connection;
  1519. if (!statement) return;
  1520. cpphibernate_debug_log("execute ALTER TABLE query: " << statement->query(connection));
  1521. connection.execute(*statement);
  1522. }
  1523. std::string table_t::create_update_intern(const create_update_context& context) const
  1524. { return create_update_exec(context); }
  1525. std::string table_t::create_update_exec(const create_update_context& context) const
  1526. {
  1527. auto* statement = context.is_update
  1528. ? get_statement_update(context.filter, context.owner_field)
  1529. : get_statement_insert_into();
  1530. return execute_create_update(context, statement);
  1531. }
  1532. void table_t::read_exec(const read_context& context) const
  1533. {
  1534. auto& statement = get_statement_select(context);
  1535. auto& connection = context.connection;
  1536. statement.set(0, context.where);
  1537. statement.set(1, context.order_by);
  1538. statement.set(2, context.limit);
  1539. cpphibernate_debug_log("execute SELECT query: " << statement.query(connection));
  1540. auto result = connection.execute_used(statement);
  1541. if (!result)
  1542. throw misc::hibernate_exception("Unable to fetching data from database!");
  1543. ::cppmariadb::row* row;
  1544. foreign_many_list_t foreign_many_list;
  1545. while ((row = result->next()))
  1546. data_extractor_t(*this, context, *row, foreign_many_list)();
  1547. context.finish();
  1548. for (auto& tuple : foreign_many_list)
  1549. {
  1550. auto& field = tuple.field;
  1551. auto& next_context = *tuple.context;
  1552. assert(field.table);
  1553. assert(field.referenced_table);
  1554. assert(field.referenced_table->primary_key_field);
  1555. auto& ref_table = *field.referenced_table;
  1556. auto& ref_field = *ref_table.primary_key_field;
  1557. {
  1558. std::ostringstream ss;
  1559. ss << "WHERE (`"
  1560. << ref_table.table_name
  1561. << "`.`"
  1562. << field.table_name
  1563. << "_id_"
  1564. << field.field_name
  1565. << "`="
  1566. << ref_field.convert_to_open
  1567. << "'"
  1568. << context.connection.escape(tuple.owner)
  1569. << "'"
  1570. << ref_field.convert_to_close
  1571. << ")";
  1572. next_context.where = ss.str();
  1573. }
  1574. {
  1575. std::ostringstream ss;
  1576. ss << "ORDER BY `"
  1577. << ref_table.table_name
  1578. << "`.`"
  1579. << field.table_name
  1580. << "_index_"
  1581. << field.field_name
  1582. << "` ASC";
  1583. next_context.order_by = ss.str();
  1584. }
  1585. ref_table.read(next_context);
  1586. }
  1587. }
  1588. void table_t::destroy_intern(const destroy_context& context) const
  1589. { return destroy_exec(context); }
  1590. void table_t::destroy_exec(const destroy_context& context) const
  1591. {
  1592. assert(primary_key_field);
  1593. auto& connection = context.connection;
  1594. auto& statement = get_statement_delete();
  1595. statement.set(0, context.where);
  1596. cpphibernate_debug_log("execute DELETE query: " << statement.query(connection));
  1597. connection.execute(statement);
  1598. table_set processed;
  1599. for (auto& ptr : foreign_table_fields)
  1600. {
  1601. assert(ptr);
  1602. assert(ptr->referenced_table);
  1603. auto& ref_table = *ptr->referenced_table;
  1604. if (ref_table.is_used_in_container)
  1605. ref_table.destroy_cleanup(context, processed, true, true);
  1606. }
  1607. }
  1608. void table_t::destroy_cleanup(const base_context& context, table_set& processed, bool check_derived, bool check_base) const
  1609. {
  1610. if (processed.count(this))
  1611. return;
  1612. processed.emplace(this);
  1613. execute_foreign_many_delete(context);
  1614. for (auto ptr : foreign_table_fields)
  1615. {
  1616. assert(ptr);
  1617. assert(ptr->referenced_table);
  1618. auto& ref_table = *ptr->referenced_table;
  1619. if (ref_table.is_used_in_container)
  1620. ref_table.destroy_cleanup(context, processed, true, true);
  1621. }
  1622. if (check_base && base_table)
  1623. {
  1624. base_table->destroy_cleanup(context, processed, false, true);
  1625. }
  1626. if (check_derived)
  1627. {
  1628. for (auto ptr : derived_tables)
  1629. {
  1630. assert(ptr);
  1631. ptr->destroy_cleanup(context, processed, true, false);
  1632. }
  1633. }
  1634. }