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.
 
 
 

466 lines
13 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. std::string key = table.base_table->create_update_exec(new_context);
  254. if (statement) statement->set(index, std::move(key));
  255. ++index;
  256. }
  257. if (is_update && filter->is_excluded(table))
  258. return primary_key;
  259. /* foreign table one fields */
  260. for (auto& ptr : table.foreign_table_one_fields)
  261. {
  262. assert(ptr);
  263. assert(ptr->referenced_table);
  264. auto& field = *ptr;
  265. if (is_update && filter->is_excluded(field))
  266. continue;
  267. if (field.referenced_table->is_used_in_container)
  268. continue;
  269. /* insert/update dataset */
  270. value_t key = field.foreign_create_update(context);
  271. if (key.has_value())
  272. {
  273. if (statement) statement->set(index, *key);
  274. }
  275. else if (field.value_is_nullable)
  276. {
  277. if (statement) statement->set_null(index);
  278. }
  279. else
  280. {
  281. throw exception("Received null key for non nullable foreign dataset!");
  282. }
  283. ++index;
  284. /* cleanup old dataset (if new one was created) */
  285. if (context.is_update())
  286. {
  287. field.foreign_one_delete(context, primary_key, key);
  288. }
  289. }
  290. /* foreign key fields */
  291. for (auto& ptr : table.foreign_key_fields)
  292. {
  293. assert(ptr);
  294. if (is_update && ptr != context.owner_field)
  295. continue;
  296. auto& field_info = *ptr;
  297. bool set_value =
  298. context.owner_field
  299. && ptr == context.owner_field;
  300. if (set_value)
  301. {
  302. assert(!context.owner_key.empty());
  303. if (statement) statement->set(index, context.owner_key);
  304. }
  305. else
  306. {
  307. if (statement) statement->set_null(index);
  308. }
  309. ++index;
  310. if (field_info.value_is_ordered)
  311. {
  312. if (set_value)
  313. {
  314. if (statement) statement->set(index, context.index);
  315. }
  316. else
  317. {
  318. if (statement) statement->set(index, 0);
  319. }
  320. ++index;
  321. }
  322. }
  323. /* data fields */
  324. for (auto& ptr : table.data_fields)
  325. {
  326. assert(ptr);
  327. if (is_update && filter->is_excluded(*ptr))
  328. continue;
  329. auto& field_info = *ptr;
  330. auto value = field_info.get(context);
  331. if (value.has_value())
  332. {
  333. if (statement) statement->set(index, *value);
  334. }
  335. else
  336. {
  337. if (statement) statement->set_null(index);
  338. }
  339. ++index;
  340. }
  341. /* type field for derived tables */
  342. if ( !table.derived_tables.empty()
  343. && !table.base_table
  344. && is_create)
  345. {
  346. if (statement) statement->set(index, context.derived_table
  347. ? context.derived_table->id
  348. : table.id);
  349. ++index;
  350. }
  351. /* where primary key (for update) */
  352. if (is_update)
  353. {
  354. assert(table.primary_key_field);
  355. if (statement) statement->set(index, *table.primary_key_field->get(context));
  356. ++index;
  357. }
  358. /* execute */
  359. if (statement)
  360. {
  361. if (is_create)
  362. {
  363. cpphibernate_log_debug("execute INSERT query: " << std::endl << statement->query(connection) << std::endl);
  364. }
  365. else
  366. {
  367. cpphibernate_log_debug("execute UPDATE query: " << std::endl << statement->query(connection) << std::endl);
  368. }
  369. if ( table.primary_key_field->value_is_auto_incremented
  370. && is_create)
  371. {
  372. auto id = connection.execute_id(*statement);
  373. primary_key = cppcore::to_string(id);
  374. }
  375. else
  376. {
  377. auto count = connection.execute_rows(*statement);
  378. if (count > 1)
  379. throw exception("Expected one/ row to be inserted/updated!");
  380. cpphibernate_log_debug(count << " rows inserted/updated" << std::endl);
  381. }
  382. table.primary_key_field->set(context, primary_key);
  383. }
  384. /* foreign table many fields */
  385. for (auto& ptr : table.foreign_table_fields)
  386. {
  387. assert(ptr);
  388. assert(ptr->referenced_table);
  389. auto& field = *ptr;
  390. auto& ref_table = *field.referenced_table;
  391. if (!ref_table.is_used_in_container)
  392. continue;
  393. if ( is_update
  394. && ( filter->is_excluded(field)
  395. || filter->is_excluded(ref_table)))
  396. continue;
  397. /* set foreign keys of existing elements to null */
  398. if (context.is_update())
  399. {
  400. field.foreign_many_update(context, primary_key);
  401. }
  402. /* update elements */
  403. auto next_context = context;
  404. next_context.owner_field = ptr;
  405. next_context.owner_key = primary_key;
  406. next_context.derived_table = nullptr;
  407. field.foreign_create_update(next_context);
  408. /* delete non referenced elements */
  409. if (context.is_update())
  410. {
  411. table_t::table_set processed;
  412. ref_table.cleanup(context, processed, true, true);
  413. }
  414. }
  415. return primary_key;
  416. }