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.
 
 
 

710 line
22 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.h>
  9. using namespace ::utl;
  10. using namespace ::cpphibernate::driver::mariadb_impl;
  11. /* build queries */
  12. std::string build_create_table_query(const table_t& table)
  13. {
  14. std::ostringstream os;
  15. /* CREATE TABLE */
  16. os << "CREATE TABLE IF NOT EXISTS `"
  17. << table.table_name
  18. << "`"
  19. << indent
  20. << "("
  21. << incindent;
  22. /* primary key */
  23. {
  24. assert(table.primary_key_field);
  25. auto& key_info = *table.primary_key_field;
  26. auto args = key_info.create_table_arguments();
  27. os << indent
  28. << "`"
  29. << key_info.field_name
  30. << "` "
  31. << key_info.type()
  32. << " NOT NULL"
  33. << (args.empty() ? "" : " ")
  34. << args
  35. << ",";
  36. }
  37. /* base table key fields */
  38. if (static_cast<bool>(table.base_table))
  39. {
  40. auto& base_table_info = *table.base_table;
  41. assert(base_table_info.primary_key_field);
  42. auto& key_info = *base_table_info.primary_key_field;
  43. os << indent
  44. << "`"
  45. << key_info.field_name
  46. << "` "
  47. << key_info.type()
  48. << " NOT NULL,";
  49. }
  50. /* foreign table one fields */
  51. for (auto& ptr : table.foreign_table_one_fields)
  52. {
  53. assert(static_cast<bool>(ptr));
  54. auto& field_info = *ptr;
  55. assert(field_info.referenced_table);
  56. assert(field_info.referenced_table->primary_key_field);
  57. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  58. os << indent
  59. << "`"
  60. << ref_key_info.table_name
  61. << "_id_"
  62. << field_info.field_name
  63. << "` "
  64. << ref_key_info.type()
  65. << (field_info.value_is_nullable
  66. ? " NULL DEFAULT NULL,"
  67. : " NOT NULL,");
  68. }
  69. /* foreign fields */
  70. for (auto& ptr : table.foreign_key_fields)
  71. {
  72. assert(static_cast<bool>(ptr));
  73. auto& field_info = *ptr;
  74. assert(field_info.table);
  75. assert(field_info.table->primary_key_field);
  76. auto& ref_key_info = *field_info.table->primary_key_field;
  77. os << indent
  78. << "`"
  79. << field_info.table_name
  80. << "_id_"
  81. << field_info.field_name
  82. << "` "
  83. << ref_key_info.type()
  84. << " NULL DEFAULT NULL,";
  85. }
  86. /* data fields */
  87. for (auto& ptr : table.data_fields)
  88. {
  89. assert(static_cast<bool>(ptr));
  90. auto& field_info = *ptr;
  91. os << indent
  92. << "`"
  93. << field_info.field_name
  94. << "` "
  95. << field_info.type()
  96. << (field_info.value_is_nullable
  97. ? " NULL DEFAULT NULL,"
  98. : " NOT NULL,");
  99. }
  100. /* type field for derived tables */
  101. if (!table.derived_tables.empty() &&
  102. !table.base_table)
  103. {
  104. os << indent
  105. << "`__type` INT UNSIGNED NOT NULL,";
  106. }
  107. /* PRIMARY KEY */
  108. {
  109. assert(table.primary_key_field);
  110. auto& key_info = *table.primary_key_field;
  111. os << indent
  112. << "PRIMARY KEY ( `"
  113. << key_info.field_name
  114. << "` )";
  115. }
  116. /* UNIQUE INDEX primary key */
  117. {
  118. assert(table.primary_key_field);
  119. auto& key_info = *table.primary_key_field;
  120. os << ','
  121. << indent
  122. << "UNIQUE INDEX `index_"
  123. << key_info.field_name
  124. << "` ( `"
  125. << key_info.field_name
  126. << "` ASC )";
  127. }
  128. /* UNIQUE INDEX base table keys */
  129. if (table.base_table)
  130. {
  131. auto& table_info = *table.base_table;
  132. assert(table_info.primary_key_field);
  133. auto& key_info = *table_info.primary_key_field;
  134. os << ','
  135. << indent
  136. << "UNIQUE INDEX `index_"
  137. << key_info.field_name
  138. << "` ( `"
  139. << key_info.field_name
  140. << "` ASC )";
  141. }
  142. /* INDEX foreign table one fields */
  143. for (auto& ptr : table.foreign_table_one_fields)
  144. {
  145. assert(static_cast<bool>(ptr));
  146. auto& field_info = *ptr;
  147. assert(field_info.referenced_table);
  148. assert(field_info.referenced_table->primary_key_field);
  149. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  150. os << ","
  151. << indent
  152. << "INDEX `index_"
  153. << ref_key_info.table_name
  154. << "_id_"
  155. << field_info.field_name
  156. << "` ( `"
  157. << ref_key_info.table_name
  158. << "_id_"
  159. << field_info.field_name
  160. << "` ASC )";
  161. }
  162. /* INDEX foreign fields */
  163. for (auto& ptr : table.foreign_key_fields)
  164. {
  165. assert(static_cast<bool>(ptr));
  166. auto& field_info = *ptr;
  167. os << ","
  168. << indent
  169. << "INDEX `index_"
  170. << field_info.table_name
  171. << "_id_"
  172. << field_info.field_name
  173. << "` ( `"
  174. << field_info.table_name
  175. << "_id_"
  176. << field_info.field_name
  177. << "` ASC )";
  178. }
  179. /* CONSTRAINT base table */
  180. if (table.base_table)
  181. {
  182. assert(table.base_table->primary_key_field);
  183. auto& ref_key_info = *table.base_table->primary_key_field;
  184. os << ","
  185. << indent
  186. << "CONSTRAINT `fk_"
  187. << table.table_name
  188. << "_to_"
  189. << ref_key_info.field_name
  190. << "`"
  191. << incindent
  192. << indent
  193. << "FOREIGN KEY (`"
  194. << ref_key_info.field_name
  195. << "`)"
  196. << indent
  197. << "REFERENCES `"
  198. << ref_key_info.schema_name
  199. << "`.`"
  200. << ref_key_info.table_name
  201. << "` (`"
  202. << ref_key_info.field_name
  203. << "`)"
  204. << indent
  205. << "ON DELETE CASCADE"
  206. << indent
  207. << "ON UPDATE NO ACTION"
  208. << decindent;
  209. }
  210. /* CONSTRAINT foreign table one fields */
  211. for (auto& ptr : table.foreign_table_one_fields)
  212. {
  213. assert(static_cast<bool>(ptr));
  214. auto& field_info = *ptr;
  215. assert(field_info.referenced_table);
  216. assert(field_info.referenced_table->primary_key_field);
  217. auto& ref_key_info = *field_info.referenced_table->primary_key_field;
  218. os << ","
  219. << indent
  220. << "CONSTRAINT `fk_"
  221. << table.table_name
  222. << "_to_"
  223. << ref_key_info.table_name
  224. << "_id_"
  225. << field_info.field_name
  226. << "`"
  227. << incindent
  228. << indent
  229. << "FOREIGN KEY (`"
  230. << ref_key_info.table_name
  231. << "_id_"
  232. << field_info.field_name
  233. << "`)"
  234. << indent
  235. << "REFERENCES `"
  236. << ref_key_info.schema_name
  237. << "`.`"
  238. << ref_key_info.table_name
  239. << "` (`"
  240. << ref_key_info.field_name
  241. << "`)"
  242. << indent
  243. << "ON DELETE CASCADE"
  244. << indent
  245. << "ON UPDATE NO ACTION"
  246. << decindent;
  247. }
  248. /* CONSTRAINT foreign fields */
  249. for (auto& ptr : table.foreign_key_fields)
  250. {
  251. assert(static_cast<bool>(ptr));
  252. auto& field_info = *ptr;
  253. assert(field_info.table);
  254. assert(field_info.table->primary_key_field);
  255. auto& ref_key_info = *field_info.table->primary_key_field;
  256. os << ","
  257. << indent
  258. << "CONSTRAINT `fk_"
  259. << table.table_name
  260. << "_"
  261. << field_info.table_name
  262. << "_id_"
  263. << field_info.field_name
  264. << "`"
  265. << incindent
  266. << indent
  267. << "FOREIGN KEY (`"
  268. << field_info.table_name
  269. << "_id_"
  270. << field_info.field_name
  271. << "`)"
  272. << indent
  273. << "REFERENCES `"
  274. << ref_key_info.schema_name
  275. << "`.`"
  276. << ref_key_info.table_name
  277. << "` (`"
  278. << ref_key_info.field_name
  279. << "`)"
  280. << indent
  281. << "ON DELETE SET NULL"
  282. << indent
  283. << "ON UPDATE NO ACTION"
  284. << decindent;
  285. }
  286. /* CREATE TABLE end */
  287. os << decindent
  288. << indent
  289. << ")"
  290. << indent
  291. << "ENGINE = InnoDB"
  292. << indent
  293. << "DEFAULT CHARACTER SET = utf8";
  294. return os.str();
  295. }
  296. std::string build_insert_update_query(const table_t& table, const filter_t* filter, const field_t* owner)
  297. {
  298. std::ostringstream os;
  299. size_t index = 0;
  300. bool is_update = static_cast<bool>(filter);
  301. /* INSER INTO / UPDATE */
  302. os << (is_update
  303. ? "UPDATE"
  304. : "INSERT INTO")
  305. << " `"
  306. << table.table_name
  307. << "` SET ";
  308. /* primary key */
  309. if (!is_update)
  310. {
  311. assert(table.primary_key_field);
  312. auto& key_info = *table.primary_key_field;
  313. if (!key_info.is_auto_generated())
  314. {
  315. if (index++)
  316. os << ", ";
  317. os << "`"
  318. << key_info.field_name
  319. << "`="
  320. << key_info.convert_to_open()
  321. << "?"
  322. << key_info.field_name
  323. << "?"
  324. << key_info.convert_to_close();
  325. }
  326. }
  327. /* base table key fields */
  328. if ( static_cast<bool>(table.base_table)
  329. && ( !is_update
  330. || filter->contains(table.base_table, true)))
  331. {
  332. if (index++)
  333. os << ", ";
  334. auto& base_table_info = *table.base_table;
  335. assert(base_table_info.primary_key_field);
  336. auto& key_info = *base_table_info.primary_key_field;
  337. os << "`"
  338. << key_info.field_name
  339. << "`="
  340. << key_info.convert_to_open()
  341. << "?"
  342. << key_info.field_name
  343. << "?"
  344. << key_info.convert_to_close();
  345. }
  346. /* foreign table one fields */
  347. for (auto& ptr : table.foreign_table_one_fields)
  348. {
  349. assert(static_cast<bool>(ptr));
  350. if (is_update && !filter->contains(ptr))
  351. continue;
  352. if (index++)
  353. os << ", ";
  354. auto& field_info = *ptr;
  355. assert(field_info.referenced_table);
  356. assert(field_info.referenced_table->primary_key_field);
  357. auto& key_info = *field_info.referenced_table->primary_key_field;
  358. os << "`"
  359. << key_info.table_name
  360. << "_id_"
  361. << field_info.field_name
  362. << "`="
  363. << key_info.convert_to_open()
  364. << "?"
  365. << key_info.table_name
  366. << "_id_"
  367. << field_info.field_name
  368. << "?"
  369. << key_info.convert_to_close();
  370. }
  371. /* foreign fields */
  372. for (auto& ptr : table.foreign_key_fields)
  373. {
  374. assert(static_cast<bool>(ptr));
  375. if (is_update && ptr != owner)
  376. continue;
  377. if (index++)
  378. os << ", ";
  379. auto& field_info = *ptr;
  380. assert(field_info.table);
  381. assert(field_info.table->primary_key_field);
  382. auto& key_info = *field_info.table->primary_key_field;
  383. os << "`"
  384. << field_info.table_name
  385. << "_id_"
  386. << field_info.field_name
  387. << "`="
  388. << key_info.convert_to_open()
  389. << "?"
  390. << field_info.table_name
  391. << "_id_"
  392. << field_info.field_name
  393. << "?"
  394. << key_info.convert_to_close();
  395. }
  396. /* data fields */
  397. for (auto& ptr : table.data_fields)
  398. {
  399. if (is_update && !filter->contains(ptr))
  400. continue;
  401. if (index++)
  402. os << ", ";
  403. assert(static_cast<bool>(ptr));
  404. auto& field_info = *ptr;
  405. os << "`"
  406. << field_info.field_name
  407. << "`="
  408. << field_info.convert_to_open()
  409. << "?"
  410. << field_info.field_name
  411. << "?"
  412. << field_info.convert_to_close();
  413. }
  414. /* type field for derived tables */
  415. if (!table.derived_tables.empty() &&
  416. !table.base_table)
  417. {
  418. if (index++)
  419. os << ", ";
  420. os << "`__type`=?__type?";
  421. }
  422. /* where primary key (for update) */
  423. if (is_update)
  424. {
  425. assert(table.primary_key_field);
  426. auto& key_info = *table.primary_key_field;
  427. os << " WHERE `"
  428. << key_info.field_name
  429. << "`="
  430. << key_info.convert_to_open()
  431. << "?"
  432. << key_info.field_name
  433. << "?"
  434. << key_info.convert_to_close();
  435. }
  436. return os.str();
  437. }
  438. /* execute_insert_update */
  439. std::string table_t::execute_insert_update(
  440. const create_update_context& context,
  441. ::cppmariadb::statement& statement,
  442. const filter_t* filter) const
  443. {
  444. auto& connection = context.connection;
  445. size_t index = 0;
  446. bool is_update = static_cast<bool>(filter);
  447. std::string primary_key;
  448. statement.clear();
  449. /* primary key */
  450. assert(primary_key_field);
  451. if ( !primary_key_field->is_auto_generated()
  452. && !is_update)
  453. {
  454. primary_key = primary_key_field->generate_value(context.connection);
  455. statement.set(index, primary_key);
  456. ++index;
  457. }
  458. else
  459. {
  460. primary_key = *primary_key_field->get();
  461. }
  462. /* base_key */
  463. if ( base_table
  464. && ( !is_update
  465. || filter->contains(base_table, true)))
  466. {
  467. auto new_context = context;
  468. if (!new_context.derived_table)
  469. new_context.derived_table = this;
  470. std::string key = create_update_base(new_context);
  471. statement.set(index, std::move(key));
  472. ++index;
  473. }
  474. if (is_update && !filter->contains(this, false))
  475. return primary_key;
  476. /* foreign table one fields */
  477. for (auto& ptr : foreign_table_one_fields)
  478. {
  479. assert(ptr);
  480. if (is_update && !filter->contains(ptr))
  481. continue;
  482. value_t key = ptr->foreign_create_update(context);
  483. if (key.has_value()) statement.set(index, std::move(key));
  484. else statement.set_null(index);
  485. ++index;
  486. }
  487. /* foreign fields */
  488. for (auto& ptr : foreign_key_fields)
  489. {
  490. if (is_update && ptr != context.owner_field)
  491. continue;
  492. if ( context.owner_field
  493. && ptr == context.owner_field)
  494. {
  495. auto& field_info = *ptr;
  496. assert(field_info.table);
  497. assert(field_info.table->primary_key_field);
  498. statement.set(index, field_info.table->primary_key_field->get());
  499. }
  500. else
  501. statement.set_null(index);
  502. ++index;
  503. }
  504. /* data fields */
  505. for (auto& ptr : data_fields)
  506. {
  507. if (is_update && !filter->contains(ptr))
  508. continue;
  509. assert(ptr);
  510. auto& field_info = *ptr;
  511. auto value = field_info.get();
  512. if (value.has_value()) statement.set(index, *value);
  513. else statement.set_null(index);
  514. ++index;
  515. }
  516. /* type field for derived tables */
  517. if (!derived_tables.empty() &&
  518. !base_table)
  519. {
  520. statement.set(index, context.derived_table
  521. ? context.derived_table->table_id
  522. : table_id);
  523. ++index;
  524. }
  525. /* where primary key (for update) */
  526. if (is_update)
  527. {
  528. assert(primary_key_field);
  529. statement.set(index, *primary_key_field->get());
  530. ++index;
  531. }
  532. /* execute */
  533. if (!is_update)
  534. {
  535. cpphibernate_debug_log("execute INSERT query: " << statement.query(connection));
  536. }
  537. else
  538. {
  539. cpphibernate_debug_log("execute UPDATE query: " << statement.query(connection));
  540. }
  541. if ( primary_key_field->is_auto_generated()
  542. && !is_update)
  543. {
  544. auto id = connection.execute_id(statement);
  545. primary_key = utl::to_string(id);
  546. }
  547. else
  548. {
  549. auto count = connection.execute_rows(statement);
  550. cpphibernate_debug_log(count << " rows inserted/updated");
  551. }
  552. primary_key_field->set(primary_key);
  553. /* foreign table many fields */
  554. for (auto& ptr : foreign_table_many_fields)
  555. {
  556. assert(ptr);
  557. if ( is_update
  558. && ( !filter->contains(ptr)
  559. || !filter->contains(ptr->referenced_table, true)))
  560. continue;
  561. auto next_context = context;
  562. next_context.owner_field = ptr;
  563. ptr->foreign_create_update(next_context);
  564. }
  565. return primary_key;
  566. }
  567. /* table_t */
  568. void table_t::print(std::ostream& os) const
  569. {
  570. os << indent << '{'
  571. << incindent
  572. << indent << "\"dataset_id\": " << dataset_id << ","
  573. << indent << "\"base_dataset_id\": " << base_dataset_id << ","
  574. << indent << "\"table_id\": " << table_id << ","
  575. << indent << "\"derived_dataset_ids\": " << misc::print_container(derived_dataset_ids, false) << ","
  576. << indent << "\"schema_name\": \"" << schema_name << "\","
  577. << indent << "\"table_name\": \"" << table_name << "\","
  578. << indent << "\"fields\":" << misc::print_container(fields, true, [](auto& os, auto& field) {
  579. field->print(os);
  580. }) << ","
  581. << indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->table_name + "\"" : "null") << ","
  582. << indent << "\"derived_tables\":" << misc::print_container(derived_tables, true, [](auto& os, auto& ptr){
  583. os << indent << '"' << ptr->table_name << '"';
  584. }) << ","
  585. << indent << "\"primary_key_field\": " << (primary_key_field ? std::string("\"") + primary_key_field->field_name + "\"" : "null") << ","
  586. << indent << "\"foreign_key_fields\": " << misc::print_container(foreign_key_fields, true, [](auto& os, auto& ptr){
  587. os << indent << '"' << ptr->table_name << '.' << ptr->field_name << '"';
  588. }) << ","
  589. << indent << "\"foreign_table_fields\": " << misc::print_container(foreign_table_fields, true, [](auto& os, auto& ptr){
  590. os << indent << '"' << ptr->field_name << '"';
  591. }) << ","
  592. << indent << "\"foreign_table_one_fields\": " << misc::print_container(foreign_table_one_fields, true, [](auto& os, auto& ptr){
  593. os << indent << '"' << ptr->field_name << '"';
  594. }) << ","
  595. << indent << "\"foreign_table_many_fields\": " << misc::print_container(foreign_table_many_fields, true, [](auto& os, auto& ptr){
  596. os << indent << '"' << ptr->field_name << '"';
  597. }) << ","
  598. << indent << "\"data_fields\": " << misc::print_container(data_fields, true, [](auto& os, auto& ptr){
  599. os << indent << '"' << ptr->field_name << '"';
  600. })
  601. << decindent
  602. << indent << '}';
  603. }
  604. const table_t* table_t::get_derived(size_t id) const
  605. {
  606. if (dataset_id == id)
  607. return this;
  608. for (auto ptr : derived_tables)
  609. {
  610. assert(ptr);
  611. auto ret = ptr->get_derived(id);
  612. if (ret) return ret;
  613. }
  614. return nullptr;
  615. }
  616. ::cppmariadb::statement& table_t::get_statement_create_table() const
  617. {
  618. if (_statement_create_table)
  619. return *_statement_create_table;
  620. auto query = build_create_table_query(*this);
  621. _statement_create_table.reset(new ::cppmariadb::statement(query));
  622. return *_statement_create_table;
  623. }
  624. ::cppmariadb::statement& table_t::get_statement_insert_into() const
  625. {
  626. if (_statement_insert_into)
  627. return *_statement_insert_into;
  628. auto query = build_insert_update_query(*this, nullptr, nullptr);
  629. _statement_create_table.reset(new ::cppmariadb::statement(query));
  630. return *_statement_create_table;
  631. }
  632. std::string table_t::create_update_base(const create_update_context& context) const
  633. {
  634. throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
  635. << "'" << this->table_name << "' does not implement create_update_base!").str());
  636. }
  637. void table_t::init_exec(const init_context& context) const
  638. {
  639. auto& statement = get_statement_create_table();
  640. auto& connection = context.connection;
  641. cpphibernate_debug_log("execute CREATE TABLE query: " << statement.query(connection));
  642. connection.execute(statement);
  643. }
  644. std::string table_t::create_update_exec(const create_update_context& context) const
  645. {
  646. auto& statement = get_statement_insert_into();
  647. return execute_insert_update(context, statement, nullptr);
  648. }
  649. std::string table_t::create_update_intern(const create_update_context& context) const
  650. { return create_update_exec(context); }