選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

425 行
11 KiB

  1. #include <cppcore/misc/indent.h>
  2. #include <cpphibernate/types.inl>
  3. #include <cpphibernate/driver/mariadb/classes/tables/table.inl>
  4. #include <cpphibernate/driver/mariadb/classes/schema/schema.inl>
  5. #include <cpphibernate/driver/mariadb/context/init_context.inl>
  6. using namespace ::cpphibernate;
  7. using namespace ::cpphibernate::mariadb;
  8. static std::string build_init_stage1_query(const table_t& table);
  9. static std::string build_init_stage2_query(const table_t& table);
  10. void table_t::init(const init_context& context, init_stage stage) const
  11. {
  12. switch (stage)
  13. {
  14. case init_stage::stage1:
  15. {
  16. auto& statement = get_statement_init_stage1();
  17. auto& connection = context.connection;
  18. cpphibernate_log_debug("execute CREATE TABLE query: " << std::endl << statement.query(connection) << std::endl);
  19. connection.execute(statement);
  20. }
  21. break;
  22. case init_stage::stage2:
  23. {
  24. auto* statement = get_statement_init_stage2();
  25. auto& connection = context.connection;
  26. if (!statement)
  27. return;
  28. cpphibernate_log_debug("execute ALTER TABLE query: " << std::endl << statement->query(connection) << std::endl);
  29. connection.execute(*statement);
  30. }
  31. break;
  32. case init_stage::unknown:
  33. throw exception("Unkown or invalid init stage!");
  34. break;
  35. }
  36. }
  37. ::cppmariadb::statement& table_t::get_statement_init_stage1() const
  38. {
  39. if (!_statement_init_stage1)
  40. _statement_init_stage1.reset(new ::cppmariadb::statement(build_init_stage1_query(*this)));
  41. return *_statement_init_stage1;
  42. }
  43. ::cppmariadb::statement* table_t::get_statement_init_stage2() const
  44. {
  45. if (!_statement_init_stage2)
  46. _statement_init_stage2.reset(new ::cppmariadb::statement(build_init_stage2_query(*this)));
  47. return _statement_init_stage2->empty()
  48. ? nullptr
  49. : _statement_init_stage2.get();
  50. }
  51. std::string build_init_stage1_query(const table_t& table)
  52. {
  53. using namespace ::cppcore;
  54. std::ostringstream os;
  55. /* CREATE TABLE */
  56. os << "CREATE TABLE IF NOT EXISTS `"
  57. << table.name
  58. << "`"
  59. << indent
  60. << "("
  61. << incindent;
  62. /* primary key */
  63. {
  64. assert(table.primary_key_field);
  65. auto& key_info = *table.primary_key_field;
  66. auto args = key_info.create_arguments;
  67. os << indent
  68. << "`"
  69. << key_info.name
  70. << "` "
  71. << key_info.type
  72. << " NOT NULL"
  73. << (args.empty() ? "" : " ")
  74. << args
  75. << ",";
  76. }
  77. /* base table key fields */
  78. if (static_cast<bool>(table.base_table))
  79. {
  80. auto& base_table_info = *table.base_table;
  81. assert(base_table_info.primary_key_field);
  82. auto& key_info = *base_table_info.primary_key_field;
  83. os << indent
  84. << "`"
  85. << key_info.name
  86. << "` "
  87. << key_info.type
  88. << " NOT NULL,";
  89. }
  90. /* foreign table one fields */
  91. for (auto& ptr : table.foreign_table_one_fields)
  92. {
  93. assert(static_cast<bool>(ptr));
  94. auto& field_info = *ptr;
  95. assert(field_info.referenced_table);
  96. auto& referenced_table = *field_info.referenced_table;
  97. if (referenced_table.is_used_in_container)
  98. continue;
  99. assert(referenced_table.primary_key_field);
  100. auto& ref_key_info = *referenced_table.primary_key_field;
  101. os << indent
  102. << "`"
  103. << ref_key_info.table.name
  104. << "_id_"
  105. << field_info.name
  106. << "` "
  107. << ref_key_info.type
  108. << (field_info.value_is_nullable
  109. ? " NULL DEFAULT NULL,"
  110. : " NOT NULL,");
  111. }
  112. /* foreign fields */
  113. for (auto& ptr : table.foreign_key_fields)
  114. {
  115. assert(static_cast<bool>(ptr));
  116. auto& field_info = *ptr;
  117. assert(field_info.table.primary_key_field);
  118. auto& ref_key_info = *field_info.table.primary_key_field;
  119. os << indent
  120. << "`"
  121. << field_info.table.name
  122. << "_id_"
  123. << field_info.name
  124. << "` "
  125. << ref_key_info.type
  126. << " NULL DEFAULT NULL,";
  127. if (field_info.value_is_ordered)
  128. {
  129. os << indent
  130. << "`"
  131. << field_info.table.name
  132. << "_index_"
  133. << field_info.name
  134. << "` INT UNSIGNED NOT NULL,";
  135. }
  136. }
  137. /* data fields */
  138. for (auto& ptr : table.data_fields)
  139. {
  140. assert(static_cast<bool>(ptr));
  141. auto& field_info = *ptr;
  142. os << indent
  143. << "`"
  144. << field_info.name
  145. << "` "
  146. << field_info.type
  147. << (field_info.value_is_nullable
  148. ? " NULL DEFAULT NULL,"
  149. : " NOT NULL,");
  150. }
  151. /* type field for derived tables */
  152. if (!table.derived_tables.empty() &&
  153. !table.base_table)
  154. {
  155. os << indent
  156. << "`__type` INT UNSIGNED NOT NULL,";
  157. }
  158. /* PRIMARY KEY */
  159. {
  160. assert(table.primary_key_field);
  161. auto& key_info = *table.primary_key_field;
  162. os << indent
  163. << "PRIMARY KEY ( `"
  164. << key_info.name
  165. << "` )";
  166. }
  167. /* UNIQUE INDEX primary key */
  168. {
  169. assert(table.primary_key_field);
  170. auto& key_info = *table.primary_key_field;
  171. os << ','
  172. << indent
  173. << "UNIQUE INDEX `index_"
  174. << key_info.name
  175. << "` ( `"
  176. << key_info.name
  177. << "` ASC )";
  178. }
  179. /* UNIQUE INDEX base table keys */
  180. if (table.base_table)
  181. {
  182. auto& table_info = *table.base_table;
  183. assert(table_info.primary_key_field);
  184. auto& key_info = *table_info.primary_key_field;
  185. os << ','
  186. << indent
  187. << "UNIQUE INDEX `index_"
  188. << key_info.name
  189. << "` ( `"
  190. << key_info.name
  191. << "` ASC )";
  192. }
  193. /* INDEX foreign table one fields */
  194. for (auto& ptr : table.foreign_table_one_fields)
  195. {
  196. assert(static_cast<bool>(ptr));
  197. auto& field_info = *ptr;
  198. assert(field_info.referenced_table);
  199. auto& referenced_table = *field_info.referenced_table;
  200. if (referenced_table.is_used_in_container)
  201. continue;
  202. assert(referenced_table.primary_key_field);
  203. auto& ref_key_info = *referenced_table.primary_key_field;
  204. os << ","
  205. << indent
  206. << "INDEX `index_"
  207. << ref_key_info.table.name
  208. << "_id_"
  209. << field_info.name
  210. << "` ( `"
  211. << ref_key_info.table.name
  212. << "_id_"
  213. << field_info.name
  214. << "` ASC )";
  215. }
  216. /* INDEX foreign fields */
  217. for (auto& ptr : table.foreign_key_fields)
  218. {
  219. assert(static_cast<bool>(ptr));
  220. auto& field_info = *ptr;
  221. os << ","
  222. << indent
  223. << "INDEX `index_"
  224. << field_info.table.name
  225. << "_id_"
  226. << field_info.name
  227. << "` ( `"
  228. << field_info.table.name
  229. << "_id_"
  230. << field_info.name
  231. << "` ASC )";
  232. }
  233. /* CREATE TABLE end */
  234. os << decindent
  235. << indent
  236. << ")"
  237. << indent
  238. << "ENGINE = InnoDB"
  239. << indent
  240. << "DEFAULT CHARACTER SET = utf8";
  241. return os.str();
  242. }
  243. std::string build_init_stage2_query(const table_t& table)
  244. {
  245. using namespace ::cppcore;
  246. std::ostringstream os;
  247. /* ALTER TABLE */
  248. os << "ALTER TABLE `"
  249. << table.name
  250. << "`"
  251. << incindent;
  252. size_t index = 0;
  253. /* CONSTRAINT base table */
  254. if (table.base_table)
  255. {
  256. assert(table.base_table->primary_key_field);
  257. auto& ref_key_info = *table.base_table->primary_key_field;
  258. if (index++) os << ",";
  259. os << indent
  260. << "ADD CONSTRAINT `fk_"
  261. << table.name
  262. << "_"
  263. << ref_key_info.name
  264. << "`"
  265. << incindent
  266. << indent
  267. << "FOREIGN KEY IF NOT EXISTS (`"
  268. << ref_key_info.name
  269. << "`)"
  270. << indent
  271. << "REFERENCES `"
  272. << ref_key_info.table.schema.name
  273. << "`.`"
  274. << ref_key_info.table.name
  275. << "` (`"
  276. << ref_key_info.name
  277. << "`)"
  278. << indent
  279. << "ON DELETE CASCADE"
  280. << indent
  281. << "ON UPDATE CASCADE"
  282. << decindent;
  283. }
  284. /* CONSTRAINT foreign table one fields */
  285. for (auto& ptr : table.foreign_table_one_fields)
  286. {
  287. assert(static_cast<bool>(ptr));
  288. auto& field_info = *ptr;
  289. assert(field_info.referenced_table);
  290. auto& referenced_table = *field_info.referenced_table;
  291. if (referenced_table.is_used_in_container)
  292. continue;
  293. assert(referenced_table.primary_key_field);
  294. auto& ref_key_info = *referenced_table.primary_key_field;
  295. if (index++) os << ",";
  296. os << indent
  297. << "ADD CONSTRAINT `fk_"
  298. << table.name
  299. << "_"
  300. << ref_key_info.table.name
  301. << "_"
  302. << field_info.name
  303. << "`"
  304. << incindent
  305. << indent
  306. << "FOREIGN KEY IF NOT EXISTS (`"
  307. << ref_key_info.table.name
  308. << "_id_"
  309. << field_info.name
  310. << "`)"
  311. << indent
  312. << "REFERENCES `"
  313. << ref_key_info.table.schema.name
  314. << "`.`"
  315. << ref_key_info.table.name
  316. << "` (`"
  317. << ref_key_info.name
  318. << "`)"
  319. << indent;
  320. if (field_info.value_is_nullable)
  321. os << "ON DELETE SET NULL";
  322. else
  323. os << "ON DELETE CASCADE";
  324. os << indent
  325. << "ON UPDATE NO ACTION"
  326. << decindent;
  327. }
  328. /* CONSTRAINT foreign fields */
  329. for (auto& ptr : table.foreign_key_fields)
  330. {
  331. assert(static_cast<bool>(ptr));
  332. auto& field_info = *ptr;
  333. assert(field_info.table.primary_key_field);
  334. auto& ref_key_info = *field_info.table.primary_key_field;
  335. if (index++) os << ",";
  336. os << indent
  337. << "ADD CONSTRAINT `fk_"
  338. << table.name
  339. << "_"
  340. << field_info.table.name
  341. << "_"
  342. << field_info.name
  343. << "`"
  344. << incindent
  345. << indent
  346. << "FOREIGN KEY IF NOT EXISTS (`"
  347. << field_info.table.name
  348. << "_id_"
  349. << field_info.name
  350. << "`)"
  351. << indent
  352. << "REFERENCES `"
  353. << ref_key_info.table.schema.name
  354. << "`.`"
  355. << ref_key_info.table.name
  356. << "` (`"
  357. << ref_key_info.name
  358. << "`)"
  359. << indent
  360. << "ON DELETE SET NULL"
  361. << indent
  362. << "ON UPDATE NO ACTION"
  363. << decindent;
  364. }
  365. return index == 0
  366. ? std::string { }
  367. : os.str();
  368. }