Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

484 rader
14 KiB

  1. #include <cpphibernate/driver/mariadb/types.h>
  2. #include <cpphibernate/types.inl>
  3. #include <cpphibernate/driver/mariadb/impl/filter.inl>
  4. #include <cpphibernate/driver/mariadb/classes/tables/table.inl>
  5. #include <cpphibernate/driver/mariadb/context/create_update_context.inl>
  6. using namespace ::cpphibernate;
  7. using namespace ::cpphibernate::mariadb;
  8. static std::string build_create_update_query(
  9. const table_t& table,
  10. const filter_t * filter,
  11. const field_t * owner);
  12. static std::string execute_create_update(
  13. const table_t& table,
  14. const create_update_context& context,
  15. ::cppmariadb::statement * statement);
  16. /* table_t */
  17. std::string table_t::create_update(const create_update_context& context) const
  18. { return create_update_exec(context); }
  19. std::string table_t::create_update_exec(const create_update_context& context) const
  20. {
  21. auto * statement = context.is_update()
  22. ? get_statement_update(*context.filter, context.owner_field)
  23. : get_statement_insert_into();
  24. return execute_create_update(*this, context, statement);
  25. }
  26. ::cppmariadb::statement* table_t::get_statement_insert_into() const
  27. {
  28. if (!_statement_insert_into)
  29. {
  30. auto query = build_create_update_query(*this, nullptr, nullptr);
  31. _statement_insert_into.reset(new ::cppmariadb::statement(query));
  32. }
  33. return _statement_insert_into->empty()
  34. ? nullptr
  35. : _statement_insert_into.get();
  36. }
  37. ::cppmariadb::statement* table_t::get_statement_update(const filter_t& filter, const field_t * owner) const
  38. {
  39. auto key = std::make_tuple(filter.cache_id, owner);
  40. auto it = _statement_update.find(key);
  41. if (it == _statement_update.end())
  42. {
  43. auto query = build_create_update_query(*this, &filter, owner);
  44. it = _statement_update.emplace(key, ::cppmariadb::statement(query)).first;
  45. }
  46. return it->second.empty()
  47. ? nullptr
  48. : &it->second;
  49. }
  50. std::string build_create_update_query(const table_t& table, const filter_t* filter, const field_t* owner)
  51. {
  52. std::ostringstream os;
  53. size_t index = 0;
  54. bool is_update = static_cast<bool>(filter);
  55. bool is_create = !is_update;
  56. /* INSER INTO / UPDATE */
  57. os << (is_update
  58. ? "UPDATE"
  59. : "INSERT INTO")
  60. << " `"
  61. << table.name
  62. << "`";
  63. /* primary key */
  64. if (is_create)
  65. {
  66. assert(table.primary_key_field);
  67. auto& key_info = *table.primary_key_field;
  68. if (!key_info.value_is_auto_incremented)
  69. {
  70. if (index++)
  71. os << ", ";
  72. else
  73. os << " SET ";
  74. os << "`"
  75. << key_info.name
  76. << "`="
  77. << key_info.convert_to_open
  78. << "?"
  79. << key_info.name
  80. << "?"
  81. << key_info.convert_to_close;
  82. }
  83. }
  84. /* base table key fields */
  85. if ( static_cast<bool>(table.base_table)
  86. && ( is_create
  87. || !filter->is_excluded(*table.base_table)))
  88. {
  89. if (index++)
  90. os << ", ";
  91. else
  92. os << " SET ";
  93. auto& base_table_info = *table.base_table;
  94. assert(base_table_info.primary_key_field);
  95. auto& key_info = *base_table_info.primary_key_field;
  96. os << "`"
  97. << key_info.name
  98. << "`="
  99. << key_info.convert_to_open
  100. << "?"
  101. << key_info.name
  102. << "?"
  103. << key_info.convert_to_close;
  104. }
  105. /* foreign table one fields */
  106. for (auto& ptr : table.foreign_table_one_fields)
  107. {
  108. assert(static_cast<bool>(ptr));
  109. auto& field_info = *ptr;
  110. if (is_update && filter->is_excluded(field_info))
  111. continue;
  112. assert(field_info.referenced_table);
  113. assert(field_info.referenced_table->primary_key_field);
  114. if (field_info.referenced_table->is_used_in_container)
  115. continue;
  116. if (index++)
  117. os << ", ";
  118. else
  119. os << " SET ";
  120. auto& key_info = *field_info.referenced_table->primary_key_field;
  121. os << "`"
  122. << key_info.table.name
  123. << "_id_"
  124. << field_info.name
  125. << "`="
  126. << key_info.convert_to_open
  127. << "?"
  128. << key_info.table.name
  129. << "_id_"
  130. << field_info.name
  131. << "?"
  132. << key_info.convert_to_close;
  133. }
  134. /* foreign fields */
  135. for (auto& ptr : table.foreign_key_fields)
  136. {
  137. assert(static_cast<bool>(ptr));
  138. if (is_update && ptr != owner)
  139. continue;
  140. if (index++)
  141. os << ", ";
  142. else
  143. os << " SET ";
  144. auto& field_info = *ptr;
  145. assert(field_info.table.primary_key_field);
  146. auto& key_info = *field_info.table.primary_key_field;
  147. os << "`"
  148. << field_info.table.name
  149. << "_id_"
  150. << field_info.name
  151. << "`="
  152. << key_info.convert_to_open
  153. << "?"
  154. << field_info.table.name
  155. << "_id_"
  156. << field_info.name
  157. << "?"
  158. << key_info.convert_to_close;
  159. if (field_info.value_is_ordered)
  160. {
  161. if (index++)
  162. os << ", ";
  163. else
  164. os << " SET ";
  165. os << "`"
  166. << field_info.table.name
  167. << "_index_"
  168. << field_info.name
  169. << "`=?\?";
  170. }
  171. }
  172. /* data fields */
  173. for (auto& ptr : table.data_fields)
  174. {
  175. assert(ptr);
  176. auto& field_info = *ptr;
  177. if (is_update && filter->is_excluded(field_info))
  178. continue;
  179. if (index++)
  180. os << ", ";
  181. else
  182. os << " SET ";
  183. os << "`"
  184. << field_info.name
  185. << "`="
  186. << field_info.convert_to_open
  187. << "?"
  188. << field_info.name
  189. << "?"
  190. << field_info.convert_to_close;
  191. }
  192. /* type field for derived tables */
  193. if ( !table.derived_tables.empty()
  194. && !table.base_table
  195. && is_create)
  196. {
  197. if (index++)
  198. os << ", ";
  199. else
  200. os << " SET ";
  201. os << "`__type`=?__type?";
  202. }
  203. /* where primary key (for update) */
  204. if (is_update)
  205. {
  206. assert(table.primary_key_field);
  207. auto& key_info = *table.primary_key_field;
  208. os << " WHERE `"
  209. << key_info.name
  210. << "`="
  211. << key_info.convert_to_open
  212. << "?"
  213. << key_info.name
  214. << "?"
  215. << key_info.convert_to_close;
  216. }
  217. return index == 0 && !(table.primary_key_field->value_is_auto_incremented && is_create)
  218. ? std::string()
  219. : os.str();
  220. }
  221. std::string execute_create_update(
  222. const table_t& table,
  223. const create_update_context& context,
  224. ::cppmariadb::statement * statement)
  225. {
  226. auto& connection = context.connection;
  227. auto* filter = context.filter;
  228. size_t index = 0;
  229. bool is_update = context.is_update();
  230. bool is_create = context.is_create();
  231. std::string primary_key;
  232. if (statement) statement->clear();
  233. /* primary key */
  234. assert(table.primary_key_field);
  235. if (is_update)
  236. {
  237. primary_key = table.get_primary_key(context);
  238. }
  239. else if (!table.primary_key_field->value_is_auto_incremented)
  240. {
  241. primary_key = table.primary_key_field->generate_value(context.connection);
  242. if (statement) statement->set(index, primary_key);
  243. ++index;
  244. }
  245. /* base_key */
  246. if ( table.base_table
  247. && ( is_create
  248. || !filter->is_excluded(*table.base_table)))
  249. {
  250. auto new_context = context;
  251. if (!new_context.derived_table)
  252. new_context.derived_table = &table;
  253. // TODO std::string key = create_update_base(new_context);
  254. std::string key = table.base_table->create_update_exec(new_context);
  255. if (statement) statement->set(index, std::move(key));
  256. ++index;
  257. }
  258. if (is_update && filter->is_excluded(table))
  259. return primary_key;
  260. /* foreign table one fields */
  261. for (auto& ptr : table.foreign_table_one_fields)
  262. {
  263. assert(ptr);
  264. assert(ptr->referenced_table);
  265. auto& field = *ptr;
  266. if (is_update && filter->is_excluded(field))
  267. continue;
  268. if (field.referenced_table->is_used_in_container)
  269. continue;
  270. /* insert/update dataset */
  271. value_t key = field.foreign_create_update(context);
  272. if (key.has_value())
  273. {
  274. if (statement) statement->set(index, *key);
  275. }
  276. else if (field.value_is_nullable)
  277. {
  278. if (statement) statement->set_null(index);
  279. }
  280. else
  281. {
  282. throw exception("Received null key for non nullable foreign dataset!");
  283. }
  284. ++index;
  285. /* cleanup old dataset (if new one was created) */
  286. if (context.is_update())
  287. {
  288. /* TODO
  289. auto& delete_statement = field.get_statement_foreign_one_delete(key.has_value());
  290. delete_statement.set(0, primary_key);
  291. if (key.has_value())
  292. delete_statement.set(1, *key);
  293. cpphibernate_log_debug("execute DELETE old foreign one query: " << std::endl << delete_statement.query(connection) << std::endl);
  294. connection.execute(delete_statement);
  295. table_set processed;
  296. field.referenced_table->destroy_cleanup(context, processed, true, true);
  297. */
  298. }
  299. }
  300. /* foreign key fields */
  301. for (auto& ptr : table.foreign_key_fields)
  302. {
  303. assert(ptr);
  304. if (is_update && ptr != context.owner_field)
  305. continue;
  306. auto& field_info = *ptr;
  307. bool set_value =
  308. context.owner_field
  309. && ptr == context.owner_field;
  310. if (set_value)
  311. {
  312. assert(!context.owner_key.empty());
  313. if (statement) statement->set(index, context.owner_key);
  314. }
  315. else
  316. {
  317. if (statement) statement->set_null(index);
  318. }
  319. ++index;
  320. if (field_info.value_is_ordered)
  321. {
  322. if (set_value)
  323. {
  324. if (statement) statement->set(index, context.index);
  325. }
  326. else
  327. {
  328. if (statement) statement->set(index, 0);
  329. }
  330. ++index;
  331. }
  332. }
  333. /* data fields */
  334. for (auto& ptr : table.data_fields)
  335. {
  336. assert(ptr);
  337. if (is_update && filter->is_excluded(*ptr))
  338. continue;
  339. auto& field_info = *ptr;
  340. auto value = field_info.get(context);
  341. if (value.has_value())
  342. {
  343. if (statement) statement->set(index, *value);
  344. }
  345. else
  346. {
  347. if (statement) statement->set_null(index);
  348. }
  349. ++index;
  350. }
  351. /* type field for derived tables */
  352. if ( !table.derived_tables.empty()
  353. && !table.base_table
  354. && is_create)
  355. {
  356. if (statement) statement->set(index, context.derived_table
  357. ? context.derived_table->id
  358. : table.id);
  359. ++index;
  360. }
  361. /* where primary key (for update) */
  362. if (is_update)
  363. {
  364. assert(table.primary_key_field);
  365. if (statement) statement->set(index, *table.primary_key_field->get(context));
  366. ++index;
  367. }
  368. /* execute */
  369. if (statement)
  370. {
  371. if (is_create)
  372. {
  373. cpphibernate_log_debug("execute INSERT query: " << std::endl << statement->query(connection) << std::endl);
  374. }
  375. else
  376. {
  377. cpphibernate_log_debug("execute UPDATE query: " << std::endl << statement->query(connection) << std::endl);
  378. }
  379. if ( table.primary_key_field->value_is_auto_incremented
  380. && is_create)
  381. {
  382. auto id = connection.execute_id(*statement);
  383. primary_key = cppcore::to_string(id);
  384. }
  385. else
  386. {
  387. auto count = connection.execute_rows(*statement);
  388. if (count > 1)
  389. throw exception("Expected one/ row to be inserted/updated!");
  390. cpphibernate_log_debug(count << " rows inserted/updated" << std::endl);
  391. }
  392. table.primary_key_field->set(context, primary_key);
  393. }
  394. /* foreign table many fields */
  395. for (auto& ptr : table.foreign_table_fields)
  396. {
  397. assert(ptr);
  398. assert(ptr->referenced_table);
  399. auto& field = *ptr;
  400. auto& ref_table = *field.referenced_table;
  401. if (!ref_table.is_used_in_container)
  402. continue;
  403. if ( is_update
  404. && ( filter->is_excluded(field)
  405. || filter->is_excluded(ref_table)))
  406. continue;
  407. /* set foreign keys of existing elements to null */
  408. if (context.is_update())
  409. {
  410. /* TODO
  411. auto& update_statement = field.get_statement_foreign_many_update();
  412. update_statement.set(0, primary_key);
  413. cpphibernate_debug_log("execute UPDATE old foreign many query: " << update_statement.query(connection));
  414. connection.execute(update_statement);
  415. */
  416. }
  417. /* update elements */
  418. auto next_context = context;
  419. next_context.owner_field = ptr;
  420. next_context.owner_key = primary_key;
  421. next_context.derived_table = nullptr;
  422. field.foreign_create_update(next_context);
  423. /* delete non referenced elements */
  424. if (context.is_update())
  425. {
  426. /* TODO
  427. table_set processed;
  428. ref_table.destroy_cleanup(context, processed, true, true);
  429. */
  430. }
  431. }
  432. return primary_key;
  433. }