1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // ddDatabaseDesign.cpp - Manages all design related info and contains all model(s) and tables.
9 //
10 //////////////////////////////////////////////////////////////////////////
11
12 #include "pgAdmin3.h"
13
14 // wxWindows headers
15 #include <wx/wx.h>
16
17 // libxml2 headers
18 #include <libxml/xmlwriter.h>
19 #include <libxml/xmlreader.h>
20
21 // App headers
22 #include "dd/ddmodel/ddDatabaseDesign.h"
23 #include "hotdraw/tools/hdSelectionTool.h"
24 #include "dd/dditems/figures/ddTableFigure.h"
25 #include "dd/dditems/figures/ddRelationshipFigure.h"
26 #include "dd/dditems/utilities/ddDataType.h"
27 #include "dd/ddmodel/ddDrawingEditor.h"
28 #include "dd/dditems/figures/xml/ddXmlStorage.h"
29 #include "dd/ddmodel/ddModelBrowser.h"
30
31
ddDatabaseDesign(wxWindow * parent,wxWindow * frmOwner)32 ddDatabaseDesign::ddDatabaseDesign(wxWindow *parent, wxWindow *frmOwner)
33 {
34 editor = new ddDrawingEditor(parent, frmOwner, this);
35 attachedBrowser = NULL;
36 }
37
~ddDatabaseDesign()38 ddDatabaseDesign::~ddDatabaseDesign()
39 {
40 if(editor)
41 delete editor;
42 }
43
getEditor()44 ddDrawingEditor *ddDatabaseDesign::getEditor()
45 {
46 return editor;
47 }
48
getView(int diagramIndex)49 hdDrawingView *ddDatabaseDesign::getView(int diagramIndex)
50 {
51 return editor->getExistingView(diagramIndex);
52 }
53
registerBrowser(ddModelBrowser * browser)54 void ddDatabaseDesign::registerBrowser(ddModelBrowser *browser)
55 {
56 attachedBrowser = browser;
57 }
58
addTableToModel(hdIFigure * figure)59 void ddDatabaseDesign::addTableToModel(hdIFigure *figure)
60 {
61 editor->addModelFigure(figure);
62 if(attachedBrowser)
63 {
64 attachedBrowser->refreshFromModel();
65 }
66 }
67
addTableToView(int diagramIndex,hdIFigure * figure)68 void ddDatabaseDesign::addTableToView(int diagramIndex, hdIFigure *figure)
69 {
70 editor->addDiagramFigure(diagramIndex, figure);
71 if(attachedBrowser)
72 {
73 attachedBrowser->refreshFromModel();
74 }
75 }
76
refreshBrowser()77 void ddDatabaseDesign::refreshBrowser()
78 {
79 if(attachedBrowser)
80 {
81 attachedBrowser->refreshFromModel();
82 }
83 }
84
removeTable(int diagramIndex,hdIFigure * figure)85 void ddDatabaseDesign::removeTable(int diagramIndex, hdIFigure *figure)
86 {
87 editor->removeDiagramFigure(diagramIndex, figure);
88 }
89
refreshDraw(int diagramIndex)90 void ddDatabaseDesign::refreshDraw(int diagramIndex)
91 {
92 editor->getExistingView(diagramIndex)->Refresh();
93 }
94
eraseDiagram(int diagramIndex)95 void ddDatabaseDesign::eraseDiagram(int diagramIndex)
96 {
97 editor->getExistingDiagram(diagramIndex)->removeAllFigures();
98 }
99
emptyModel()100 void ddDatabaseDesign::emptyModel()
101 {
102 editor->deleteAllModelFigures();
103 if(attachedBrowser)
104 {
105 attachedBrowser->refreshFromModel();
106 }
107 }
108
validateModel(wxString & errors)109 bool ddDatabaseDesign::validateModel(wxString &errors)
110 {
111 bool out = true;
112
113 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
114 hdIFigure *tmpFigure;
115 ddTableFigure *table;
116
117 while(iterator->HasNext())
118 {
119 tmpFigure = (hdIFigure *)iterator->Next();
120 if(tmpFigure->getKindId() == DDTABLEFIGURE)
121 {
122 table = (ddTableFigure *)tmpFigure;
123 if(!table->validateTable(errors))
124 {
125 out = false;
126 }
127 }
128 }
129 delete iterator;
130
131 return out;
132 }
133
generateList(wxArrayString tables,wxArrayInt options,pgConn * connection,wxString schemaName)134 wxString ddDatabaseDesign::generateList(wxArrayString tables, wxArrayInt options, pgConn *connection, wxString schemaName)
135 {
136 int i;
137
138 // Validate
139 if(tables.Count() != options.Count())
140 {
141 // shouldn't it be a WXASSERT?
142 wxMessageBox(_("Invalid number of arguments in call of function generate tables of list"), _("Error at generation process"), wxICON_ERROR | wxOK);
143 return wxEmptyString;
144 }
145
146 int tablesCount = tables.Count();
147 for(i = 0; i < tablesCount; i++)
148 {
149 ddTableFigure *table = getTable(tables[i]);
150 if(table == NULL)
151 {
152 // shouldn't it be a WXASSERT?
153 wxMessageBox(_("Metadata of table to be generated not found at database designer model"), _("Error at generation process"), wxICON_ERROR | wxOK);
154 return wxEmptyString;
155 }
156 }
157
158 // Start building of CREATE + ALTER PK(s) + ALTER UK(s) + ALTER FK(s)
159 wxString out;
160 out += wxT(" \n");
161 out += wxT("--\n-- ");
162 out += _("Generating Create sentence(s) for table(s) ");
163 out += wxT(" \n--\n");
164 out += wxT(" \n");
165 for(i = 0; i < tablesCount; i++)
166 {
167 if(options[i] == DDGENCREATE || options[i] == DDGENDROPCRE)
168 {
169 ddTableFigure *table = getTable(tables[i]);
170 if(options[i] == DDGENDROPCRE)
171 {
172 out += wxT(" \n");
173 out += wxT("DROP TABLE \"") + table->getTableName() + wxT("\";");
174 out += wxT(" \n");
175 }
176 out += wxT(" \n");
177 out += table->generateSQLCreate(schemaName);
178 out += wxT(" \n");
179 }
180 }
181 out += wxT(" \n");
182 out += wxT(" \n");
183 out += wxT(" \n");
184 out += wxT("--\n-- ");
185 out += _("Generating Pk sentence for table(s) ");
186 out += wxT(" \n--\n");
187 out += wxT(" \n");
188 out += wxT(" \n");
189 for(i = 0; i < tablesCount; i++)
190 {
191 if(options[i] == DDGENCREATE || options[i] == DDGENDROPCRE)
192 {
193 ddTableFigure *table = getTable(tables[i]);
194 out += table->generateSQLAlterPks(schemaName);
195 }
196 }
197 out += wxT(" \n");
198 out += wxT(" \n");
199 out += wxT(" \n");
200 out += wxT("--\n-- ");
201 out += _("Generating Uk sentence(s) for table(s) ");
202 out += wxT(" \n--\n");
203 out += wxT(" \n");
204 out += wxT(" \n");
205 for(i = 0; i < tablesCount; i++)
206 {
207 if(options[i] == DDGENCREATE || options[i] == DDGENDROPCRE)
208 {
209 ddTableFigure *table = getTable(tables[i]);
210 out += table->generateSQLAlterUks(schemaName);
211 }
212 }
213 out += wxT(" \n");
214 out += wxT(" \n");
215 out += wxT(" \n");
216 out += wxT("--\n-- ");
217 out += _("Generating Fk sentence(s) for table(s) ");
218 out += wxT(" \n--\n");
219 out += wxT(" \n");
220 out += wxT(" \n");
221 for(i = 0; i < tablesCount; i++)
222 {
223 if(options[i] == DDGENCREATE || options[i] == DDGENDROPCRE)
224 {
225 ddTableFigure *table = getTable(tables[i]);
226 out += table->generateSQLAlterFks(schemaName);
227 }
228 }
229
230 //Start generation of alter table instead of create
231 //Check there is some
232 int countAlter = 0;
233 for(i = 0; i < tablesCount; i++)
234 {
235 if(options[i] == DDGENALTER)
236 {
237 countAlter++;
238 }
239 }
240
241 if(countAlter > 0 && connection == NULL)
242 {
243 wxMessageBox(_("No connection found when building ALTER objects DDL."), _("Error at generation process"), wxICON_ERROR | wxOK);
244 return out;
245 }
246 else if(countAlter > 0 && connection != NULL)
247 {
248 if(schemaName.IsEmpty())
249 {
250 wxMessageBox(_("Schema defined when building ALTER TABLE DDL"), _("Error at generation process"), wxICON_ERROR | wxOK);
251 return out;
252 }
253 out += wxT(" \n");
254 out += wxT(" \n");
255 out += wxT(" \n");
256 out += wxT("--\n-- ");
257 out += _("Generating Alter table sentence(s) for table(s) ");
258 out += wxT(" \n--\n");
259 out += wxT(" \n");
260 out += wxT(" \n");
261 for(i = 0; i < tablesCount; i++)
262 {
263 if(options[i] == DDGENALTER)
264 {
265 ddTableFigure *table = getTable(tables[i]);
266 out += table->generateAltersTable(connection, schemaName, this);
267 out += wxT(" \n");
268 }
269 }
270 }
271
272 return out;
273 }
274
getModelTables()275 wxArrayString ddDatabaseDesign::getModelTables()
276 {
277 wxArrayString out;
278 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
279 hdIFigure *tmp;
280 ddTableFigure *table;
281 while(iterator->HasNext())
282 {
283 tmp = (hdIFigure *)iterator->Next();
284 if(tmp->getKindId() == DDTABLEFIGURE)
285 {
286 table = (ddTableFigure *)tmp;
287 out.Add(table->getTableName());
288 }
289 }
290 return out;
291 }
292
generateModel(wxString schemaName)293 wxString ddDatabaseDesign::generateModel(wxString schemaName)
294 {
295 wxString out;
296 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
297 hdIFigure *tmp;
298 ddTableFigure *table;
299 out += wxT(" \n");
300 out += wxT("--\n-- ");
301 out += _("Generating Create sentence(s) for table(s) ");
302 out += wxT(" \n--\n");
303 out += wxT(" \n");
304 while(iterator->HasNext())
305 {
306 tmp = (hdIFigure *)iterator->Next();
307 if(tmp->getKindId() == DDTABLEFIGURE)
308 {
309 out += wxT(" \n");
310 table = (ddTableFigure *)tmp;
311 out += table->generateSQLCreate(schemaName);
312 out += wxT(" \n");
313 }
314 }
315
316 out += wxT(" \n");
317 out += wxT(" \n");
318 out += wxT(" \n");
319 out += wxT("--\n-- ");
320 out += _("Generating Pk sentence for table(s) ");
321 out += wxT(" \n--\n");
322 out += wxT(" \n");
323 out += wxT(" \n");
324 iterator->ResetIterator();
325 while(iterator->HasNext())
326 {
327 tmp = (hdIFigure *)iterator->Next();
328 if(tmp->getKindId() == DDTABLEFIGURE)
329 {
330 table = (ddTableFigure *)tmp;
331 out += table->generateSQLAlterPks(schemaName);
332 }
333 }
334
335 out += wxT(" \n");
336 out += wxT(" \n");
337 out += wxT(" \n");
338 out += wxT("--\n-- ");
339 out += _("Generating Uk sentence(s) for table(s) ");
340 out += wxT(" \n--\n");
341 out += wxT(" \n");
342 out += wxT(" \n");
343 iterator->ResetIterator();
344 while(iterator->HasNext())
345 {
346 tmp = (hdIFigure *)iterator->Next();
347 if(tmp->getKindId() == DDTABLEFIGURE)
348 {
349 table = (ddTableFigure *)tmp;
350 out += table->generateSQLAlterUks(schemaName);
351 }
352 }
353
354 out += wxT(" \n");
355 out += wxT(" \n");
356 out += wxT(" \n");
357 out += wxT("--\n-- ");
358 out += _("Generating Fk sentence(s) for table(s) ");
359 out += wxT(" \n--\n");
360 out += wxT(" \n");
361 out += wxT(" \n");
362 iterator->ResetIterator();
363 while(iterator->HasNext())
364 {
365 tmp = (hdIFigure *)iterator->Next();
366 if(tmp->getKindId() == DDTABLEFIGURE)
367 {
368 table = (ddTableFigure *)tmp;
369 out += table->generateSQLAlterFks(schemaName);
370 }
371 }
372
373 delete iterator;
374 return out;
375 }
376
getDiagramTables(int diagramIndex)377 wxArrayString ddDatabaseDesign::getDiagramTables(int diagramIndex)
378 {
379 wxArrayString out;
380 hdIteratorBase *iterator = editor->getExistingDiagram(diagramIndex)->figuresEnumerator();
381 hdIFigure *tmp;
382 ddTableFigure *table;
383 while(iterator->HasNext())
384 {
385 tmp = (hdIFigure *)iterator->Next();
386 if(tmp->getKindId() == DDTABLEFIGURE)
387 {
388 table = (ddTableFigure *)tmp;
389 out.Add(table->getTableName());
390 }
391 }
392
393 return out;
394 }
395
generateDiagram(int diagramIndex,wxString schemaName)396 wxString ddDatabaseDesign::generateDiagram(int diagramIndex, wxString schemaName)
397 {
398 wxString out;
399 hdIteratorBase *iterator = editor->getExistingDiagram(diagramIndex)->figuresEnumerator();
400 hdIFigure *tmp;
401 ddTableFigure *table;
402 out += wxT(" \n");
403 out += wxT("--\n-- ");
404 out += _("Generating Create sentence(s) for table(s) ");
405 out += wxT(" \n--\n");
406 out += wxT(" \n");
407 while(iterator->HasNext())
408 {
409 tmp = (hdIFigure *)iterator->Next();
410 if(tmp->getKindId() == DDTABLEFIGURE)
411 {
412 out += wxT(" \n");
413 table = (ddTableFigure *)tmp;
414 out += table->generateSQLCreate(schemaName);
415 out += wxT(" \n");
416 }
417 }
418
419 out += wxT(" \n");
420 out += wxT(" \n");
421 out += wxT(" \n");
422 out += wxT("--\n-- ");
423 out += _("Generating Pk sentence for table(s) ");
424 out += wxT(" \n--\n");
425 out += wxT(" \n");
426 out += wxT(" \n");
427 iterator->ResetIterator();
428 while(iterator->HasNext())
429 {
430 tmp = (hdIFigure *)iterator->Next();
431 if(tmp->getKindId() == DDTABLEFIGURE)
432 {
433 table = (ddTableFigure *)tmp;
434 out += table->generateSQLAlterPks(schemaName);
435 }
436 }
437
438 out += wxT(" \n");
439 out += wxT(" \n");
440 out += wxT(" \n");
441 out += wxT("--\n-- ");
442 out += _("Generating Uk sentence(s) for table(s) ");
443 out += wxT(" \n--\n");
444 out += wxT(" \n");
445 out += wxT(" \n");
446 iterator->ResetIterator();
447 while(iterator->HasNext())
448 {
449 tmp = (hdIFigure *)iterator->Next();
450 if(tmp->getKindId() == DDTABLEFIGURE)
451 {
452 table = (ddTableFigure *)tmp;
453 out += table->generateSQLAlterUks(schemaName);
454 }
455 }
456
457 out += wxT(" \n");
458 out += wxT(" \n");
459 out += wxT(" \n");
460 out += wxT("--\n-- ");
461 out += _("Generating Fk sentence(s) for table(s) ");
462 out += wxT(" \n--\n");
463 out += wxT(" \n");
464 out += wxT(" \n");
465 iterator->ResetIterator();
466 while(iterator->HasNext())
467 {
468 tmp = (hdIFigure *)iterator->Next();
469 if(tmp->getKindId() == DDTABLEFIGURE)
470 {
471 table = (ddTableFigure *)tmp;
472 out += table->generateSQLAlterFks(schemaName);
473 }
474 }
475
476 delete iterator;
477 return out;
478 }
479
getSelectedTable(int diagramIndex)480 ddTableFigure *ddDatabaseDesign::getSelectedTable(int diagramIndex)
481 {
482 hdIteratorBase *iterator = editor->getExistingDiagram(diagramIndex)->figuresEnumerator();
483 hdIFigure *tmp;
484 ddTableFigure *table = NULL;
485 while(iterator->HasNext())
486 {
487 tmp = (hdIFigure *)iterator->Next();
488 if (tmp->isSelected(diagramIndex) && tmp->getKindId() == DDTABLEFIGURE)
489 table = (ddTableFigure *)tmp;
490 }
491 delete iterator;
492 return table;
493 }
494
getTable(wxString tableName)495 ddTableFigure *ddDatabaseDesign::getTable(wxString tableName)
496 {
497 ddTableFigure *out = NULL;
498 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
499 hdIFigure *tmp;
500 ddTableFigure *table;
501 while(iterator->HasNext())
502 {
503 tmp = (hdIFigure *)iterator->Next();
504 if(tmp->getKindId() == DDTABLEFIGURE)
505 {
506 table = (ddTableFigure *)tmp;
507 if(table->getTableName().IsSameAs(tableName, false))
508 {
509 out = table;
510 }
511 }
512 }
513 delete iterator;
514 return out;
515 }
516
517 #define XML_FROM_WXSTRING(s) ((xmlChar *)(const char *)s.mb_str(wxConvUTF8))
518 #define WXSTRING_FROM_XML(s) wxString((char *)s, wxConvUTF8)
519
writeXmlModel(wxString file)520 bool ddDatabaseDesign::writeXmlModel(wxString file)
521 {
522 int rc;
523
524 xmlWriter = xmlNewTextWriterFilename(file.mb_str(wxConvUTF8), 0);
525 if (xmlWriter == NULL)
526 {
527 wxMessageBox(_("Failed to write the model file!"), _("Error"), wxICON_ERROR | wxOK);
528 return false;
529 }
530 rc = xmlTextWriterStartDocument(xmlWriter, NULL, "UTF-8" , NULL);
531 if(rc < 0)
532 {
533 wxMessageBox(_("Failed to write the model file!"), _("Error"), wxICON_ERROR | wxOK);
534 return false;
535 }
536 else
537 {
538 ddXmlStorage::StartModel(xmlWriter, this);
539 //initialize IDs of tables
540 mappingNameToId.clear();
541 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
542 hdIFigure *tmp;
543 ddTableFigure *table;
544 int nextID = 10;
545
546 while(iterator->HasNext())
547 {
548 tmp = (hdIFigure *)iterator->Next();
549 if(tmp->getKindId() == DDTABLEFIGURE)
550 {
551 table = (ddTableFigure *)tmp;
552 mappingNameToId[table->getTableName()] = wxString::Format(wxT("TID%d"), nextID);
553 nextID += 10;
554 }
555 }
556 delete iterator;
557
558
559 //Create table xml info
560 iterator = editor->modelFiguresEnumerator();
561 while(iterator->HasNext())
562 {
563 tmp = (hdIFigure *)iterator->Next();
564 if(tmp->getKindId() == DDTABLEFIGURE)
565 {
566 table = (ddTableFigure *)tmp;
567 ddXmlStorage::Write(xmlWriter, table);
568 }
569 }
570 delete iterator;
571
572
573 //Create relationships xml info
574 ddRelationshipFigure *relationship;
575 iterator = editor->modelFiguresEnumerator();
576 while(iterator->HasNext())
577 {
578 tmp = (hdIFigure *)iterator->Next();
579 if(tmp->getKindId() == DDRELATIONSHIPFIGURE)
580 {
581 relationship = (ddRelationshipFigure *)tmp;
582 ddXmlStorage::Write(xmlWriter, relationship);
583 }
584 }
585 delete iterator;
586
587 //Create Diagrams xml info
588
589 ddXmlStorage::StarDiagrams(xmlWriter);
590
591 iterator = editor->diagramsEnumerator();
592 hdDrawing *tmpDiagram;
593
594 while(iterator->HasNext())
595 {
596 tmpDiagram = (hdDrawing *)iterator->Next();
597 ddXmlStorage::WriteLocal(xmlWriter, tmpDiagram);
598 }
599 delete iterator;
600
601 ddXmlStorage::EndDiagrams(xmlWriter);
602
603 //End model xml info
604 ddXmlStorage::EndModel(xmlWriter);
605 xmlTextWriterEndDocument(xmlWriter);
606 xmlFreeTextWriter(xmlWriter);
607 return true;
608 }
609 return false;
610 }
611
readXmlModel(wxString file,ctlAuiNotebook * notebook)612 bool ddDatabaseDesign::readXmlModel(wxString file, ctlAuiNotebook *notebook)
613 {
614 emptyModel();
615
616 mappingIdToName.clear();
617 //Initial Parse Model
618 xmlTextReaderPtr reader = xmlReaderForFile(file.mb_str(wxConvUTF8), NULL, 0);
619 ddXmlStorage::setModel(this);
620 ddXmlStorage::setModel(this);
621 ddXmlStorage::initialModelParse(reader);
622
623 //Parse Model
624 xmlReaderNewFile(reader, file.mb_str(wxConvUTF8), NULL, 0);
625 ddXmlStorage::setModel(this);
626 ddXmlStorage::setNotebook(notebook);
627
628 if(!ddXmlStorage::Read(reader))
629 {
630 return false;
631 }
632 xmlFreeTextReader(reader);
633 return true;
634 }
635
getTableId(wxString tableName)636 wxString ddDatabaseDesign::getTableId(wxString tableName)
637 {
638 return mappingNameToId[tableName];
639 }
640
addTableToMapping(wxString IdKey,wxString tableName)641 void ddDatabaseDesign::addTableToMapping(wxString IdKey, wxString tableName)
642 {
643 mappingIdToName[IdKey] = tableName;
644 }
645
getTableName(wxString Id)646 wxString ddDatabaseDesign::getTableName(wxString Id)
647 {
648 wxString tableName = wxEmptyString;
649
650 tablesMappingHashMap::iterator it;
651 for (it = mappingIdToName.begin(); it != mappingIdToName.end(); ++it)
652 {
653 wxString key = it->first;
654 if(key.IsSameAs(Id, false))
655 {
656 tableName = it->second;
657 break;
658 }
659 }
660 return tableName;
661 }
662
createDiagram(wxWindow * owner,wxString name,bool fromXml)663 hdDrawing *ddDatabaseDesign::createDiagram(wxWindow *owner, wxString name, bool fromXml)
664 {
665 hdDrawing *drawing = editor->createDiagram(owner, fromXml);
666 drawing->setName(name);
667 return drawing;
668 }
669
deleteDiagram(int diagramIndex,bool deleteView)670 void ddDatabaseDesign::deleteDiagram(int diagramIndex, bool deleteView)
671 {
672 editor->deleteDiagram(diagramIndex, deleteView);
673 }
674
getVersionXML()675 wxString ddDatabaseDesign::getVersionXML()
676 {
677 return wxString(_("1.0"));
678 }
679
markSchemaOn(wxArrayString tables)680 void ddDatabaseDesign::markSchemaOn(wxArrayString tables)
681 {
682
683 int i, tablesCount = tables.Count();
684 for(i = 0; i < tablesCount; i++)
685 {
686 ddTableFigure *table = getTable(tables[i]);
687 if(table != NULL) //mark on if table exists in other case do nothing
688 {
689 table->setBelongsToSchema(true);
690 }
691 }
692 }
693
unMarkSchemaOnAll()694 void ddDatabaseDesign::unMarkSchemaOnAll()
695 {
696 hdIteratorBase *iterator = editor->modelFiguresEnumerator();
697 hdIFigure *tmpFigure;
698 ddTableFigure *table;
699
700 while(iterator->HasNext())
701 {
702 tmpFigure = (hdIFigure *)iterator->Next();
703 if(tmpFigure->getKindId() == DDTABLEFIGURE)
704 {
705 table = (ddTableFigure *)tmpFigure;
706 table->setBelongsToSchema(false);
707 }
708 }
709 delete iterator;
710 }
711