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 // dlgForeignDataWrapper.cpp - PostgreSQL ForeignDataWrapper Property
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 // wxWindows headers
13 #include <wx/wx.h>
14 
15 // App headers
16 #include "pgAdmin3.h"
17 #include "utils/misc.h"
18 #include "utils/pgDefs.h"
19 
20 #include "dlg/dlgForeignDataWrapper.h"
21 #include "schema/pgForeignDataWrapper.h"
22 
23 
24 // pointer to controls
25 #define cbHandler           CTRL_COMBOBOX("cbHandler")
26 #define cbValidator         CTRL_COMBOBOX("cbValidator")
27 #define lstOptions          CTRL_LISTVIEW("lstOptions")
28 #define txtOption           CTRL_TEXT("txtOption")
29 #define txtValue            CTRL_TEXT("txtValue")
30 #define btnAdd              CTRL_BUTTON("wxID_ADD")
31 #define btnRemove           CTRL_BUTTON("wxID_REMOVE")
32 
33 
CreateDialog(frmMain * frame,pgObject * node,pgObject * parent)34 dlgProperty *pgForeignDataWrapperFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent)
35 {
36 	return new dlgForeignDataWrapper(this, frame, (pgForeignDataWrapper *)node);
37 }
38 
39 
40 BEGIN_EVENT_TABLE(dlgForeignDataWrapper, dlgSecurityProperty)
41 	EVT_TEXT(XRCID("cbHandler"),                dlgProperty::OnChange)
42 	EVT_COMBOBOX(XRCID("cbHandler"),            dlgProperty::OnChange)
43 	EVT_TEXT(XRCID("cbValidator"),              dlgProperty::OnChange)
44 	EVT_COMBOBOX(XRCID("cbValidator"),          dlgProperty::OnChange)
45 	EVT_LIST_ITEM_SELECTED(XRCID("lstOptions"), dlgForeignDataWrapper::OnSelChangeOption)
46 	EVT_TEXT(XRCID("txtOption"),                dlgForeignDataWrapper::OnChangeOptionName)
47 	EVT_BUTTON(wxID_ADD,                        dlgForeignDataWrapper::OnAddOption)
48 	EVT_BUTTON(wxID_REMOVE,                     dlgForeignDataWrapper::OnRemoveOption)
49 END_EVENT_TABLE();
50 
51 
dlgForeignDataWrapper(pgaFactory * f,frmMain * frame,pgForeignDataWrapper * node)52 dlgForeignDataWrapper::dlgForeignDataWrapper(pgaFactory *f, frmMain *frame, pgForeignDataWrapper *node)
53 	: dlgSecurityProperty(f, frame, node, wxT("dlgForeignDataWrapper"), wxT("USAGE"), "U")
54 {
55 	fdw = node;
56 }
57 
58 
GetObject()59 pgObject *dlgForeignDataWrapper::GetObject()
60 {
61 	return fdw;
62 }
63 
64 
Go(bool modal)65 int dlgForeignDataWrapper::Go(bool modal)
66 {
67 	wxString val;
68 
69 	if(!connection->BackendMinimumVersion(9, 1))
70 		cbHandler->Disable();
71 
72 	// Fill handler combobox
73 	cbHandler->Append(wxT(""));
74 	pgSet *set = connection->ExecuteSet(
75 	                 wxT("SELECT nspname, proname\n")
76 	                 wxT("  FROM pg_proc p\n")
77 	                 wxT("  JOIN pg_namespace nsp ON nsp.oid=pronamespace\n")
78 	                 wxT(" WHERE pronargs=0")
79 	                 wxT(" AND prorettype=") + NumToStr(PGOID_TYPE_HANDLER));
80 	if (set)
81 	{
82 		while (!set->Eof())
83 		{
84 			wxString procname = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
85 			cbHandler->Append(procname);
86 			set->MoveNext();
87 		}
88 		delete set;
89 	}
90 	cbHandler->SetSelection(0);
91 
92 	// Fill validator combobox
93 	cbValidator->Append(wxT(""));
94 	set = connection->ExecuteSet(
95 	          wxT("SELECT nspname, proname\n")
96 	          wxT("  FROM pg_proc p\n")
97 	          wxT("  JOIN pg_namespace nsp ON nsp.oid=pronamespace\n")
98 	          wxT(" WHERE proargtypes[0]=") + NumToStr(PGOID_TYPE_TEXT_ARRAY) +
99 	          wxT(" AND proargtypes[1]=") + NumToStr(PGOID_TYPE_OID));
100 	if (set)
101 	{
102 		while (!set->Eof())
103 		{
104 			wxString procname = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
105 			cbValidator->Append(procname);
106 			set->MoveNext();
107 		}
108 		delete set;
109 	}
110 	cbValidator->SetSelection(0);
111 
112 	// Initialize options listview and buttons
113 	lstOptions->AddColumn(_("Option"), 80);
114 	lstOptions->AddColumn(_("Value"), 40);
115 	txtOption->SetValue(wxT(""));
116 	txtValue->SetValue(wxT(""));
117 	btnAdd->Disable();
118 	btnRemove->Disable();
119 
120 	if (fdw)
121 	{
122 		// edit mode
123 		txtName->Enable(connection->BackendMinimumVersion(9, 2));
124 
125 		val = fdw->GetHandlerProc();
126 		if (!val.IsEmpty())
127 		{
128 			for (unsigned int i = 0 ; i < cbHandler->GetCount() ; i++)
129 			{
130 				if (cbHandler->GetString(i) == val)
131 					cbHandler->SetSelection(i);
132 			}
133 		}
134 
135 		val = fdw->GetValidatorProc();
136 		if (!val.IsEmpty())
137 		{
138 			for (unsigned int i = 0 ; i < cbValidator->GetCount() ; i++)
139 			{
140 				if (cbValidator->GetString(i) == val)
141 					cbValidator->SetSelection(i);
142 			}
143 		}
144 
145 		wxString options = fdw->GetOptions();
146 		wxString option, optionname, optionvalue;
147 		while (options.Length() > 0)
148 		{
149 			option = options.BeforeFirst(',');
150 			optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
151 			optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
152 			lstOptions->AppendItem(optionname, optionvalue);
153 			options = options.AfterFirst(',');
154 		}
155 	}
156 	else
157 	{
158 		// create mode
159 	}
160 
161 	return dlgSecurityProperty::Go(modal);
162 }
163 
164 
CreateObject(pgCollection * collection)165 pgObject *dlgForeignDataWrapper::CreateObject(pgCollection *collection)
166 {
167 	wxString name = txtName->GetValue();
168 
169 	pgObject *obj = foreignDataWrapperFactory.CreateObjects(collection, 0, wxT("\n   AND fdwname ILIKE ") + qtDbString(name));
170 	return obj;
171 }
172 
173 
CheckChange()174 void dlgForeignDataWrapper::CheckChange()
175 {
176 	bool didChange = true;
177 	wxString name = txtName->GetValue();
178 	if (fdw)
179 	{
180 		didChange = name != fdw->GetName()
181 		            || cbOwner->GetValue() != fdw->GetOwner()
182 		            || txtComment->GetValue() != fdw->GetComment()
183 		            || cbHandler->GetValue() != fdw->GetHandlerProc()
184 		            || cbValidator->GetValue() != fdw->GetValidatorProc()
185 		            || GetOptionsSql().Length() > 0;
186 		EnableOK(didChange);
187 	}
188 	else
189 	{
190 		bool enable = true;
191 
192 		CheckValid(enable, !name.IsEmpty(), _("Please specify name."));
193 		EnableOK(enable);
194 	}
195 }
196 
197 
198 
OnChangeOptionName(wxCommandEvent & ev)199 void dlgForeignDataWrapper::OnChangeOptionName(wxCommandEvent &ev)
200 {
201 	btnAdd->Enable(txtOption->GetValue().Length() > 0);
202 }
203 
204 
OnSelChangeOption(wxListEvent & ev)205 void dlgForeignDataWrapper::OnSelChangeOption(wxListEvent &ev)
206 {
207 	int row = lstOptions->GetSelection();
208 	if (row >= 0)
209 	{
210 		txtOption->SetValue(lstOptions->GetText(row, 0));
211 		txtValue->SetValue(lstOptions->GetText(row, 1));
212 	}
213 
214 	btnRemove->Enable(row >= 0);
215 }
216 
217 
OnAddOption(wxCommandEvent & ev)218 void dlgForeignDataWrapper::OnAddOption(wxCommandEvent &ev)
219 {
220 	bool found = false;
221 
222 	for (int pos = 0 ; pos < lstOptions->GetItemCount() ; pos++)
223 	{
224 		if (lstOptions->GetText(pos).IsSameAs(txtOption->GetValue(), false))
225 		{
226 			lstOptions->SetItem(pos, 1, txtValue->GetValue());
227 			found = true;
228 			break;
229 		}
230 	}
231 
232 	if (!found)
233 	{
234 		lstOptions->AppendItem(txtOption->GetValue(), txtValue->GetValue());
235 	}
236 
237 	txtOption->SetValue(wxT(""));
238 	txtValue->SetValue(wxT(""));
239 	btnAdd->Disable();
240 
241 	CheckChange();
242 }
243 
244 
OnRemoveOption(wxCommandEvent & ev)245 void dlgForeignDataWrapper::OnRemoveOption(wxCommandEvent &ev)
246 {
247 	int sel = lstOptions->GetSelection();
248 	lstOptions->DeleteItem(sel);
249 
250 	txtOption->SetValue(wxT(""));
251 	txtValue->SetValue(wxT(""));
252 	btnRemove->Disable();
253 
254 	CheckChange();
255 }
256 
257 
GetOptionsSql()258 wxString dlgForeignDataWrapper::GetOptionsSql()
259 {
260 	wxString options = fdw->GetOptions();
261 	wxString option, optionname, optionvalue, sqloptions;
262 	bool found;
263 	int pos;
264 
265 	while (options.Length() > 0)
266 	{
267 		option = options.BeforeFirst(',');
268 		optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
269 		optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
270 
271 		// check for options
272 		found = false;
273 		for (pos = 0 ; pos < lstOptions->GetItemCount() && !found; pos++)
274 		{
275 			found = lstOptions->GetText(pos, 0).Cmp(optionname) == 0;
276 			if (found) break;
277 		}
278 
279 		if (found)
280 		{
281 			if (lstOptions->GetText(pos, 1).Cmp(optionvalue) != 0)
282 			{
283 				if (sqloptions.Length() > 0)
284 					sqloptions += wxT(", ");
285 				sqloptions += wxT("SET ") + optionname + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("'");
286 			}
287 		}
288 		else
289 		{
290 			if (sqloptions.Length() > 0)
291 				sqloptions += wxT(", ");
292 			sqloptions += wxT("DROP ") + optionname;
293 		}
294 
295 		options = options.AfterFirst(',');
296 	}
297 
298 	for (pos = 0 ; pos < lstOptions->GetItemCount() ; pos++)
299 	{
300 		options = fdw->GetOptions();
301 		found = false;
302 
303 		while (options.Length() > 0 && !found)
304 		{
305 			option = options.BeforeFirst(',');
306 			optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
307 			found = lstOptions->GetText(pos, 0).Cmp(optionname) == 0;
308 			options = options.AfterFirst(',');
309 		}
310 
311 		if (!found)
312 		{
313 			optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
314 
315 			if (sqloptions.Length() > 0)
316 				sqloptions += wxT(", ");
317 			sqloptions += wxT("ADD ") + lstOptions->GetText(pos, 0) + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("'");
318 		}
319 	}
320 
321 	return sqloptions;
322 }
323 
324 
GetSql()325 wxString dlgForeignDataWrapper::GetSql()
326 {
327 	wxString sql, name;
328 	name = txtName->GetValue();
329 
330 	if (fdw)
331 	{
332 		// edit mode
333 		sql = wxEmptyString;
334 
335 		AppendNameChange(sql);
336 
337 		if (cbHandler->GetValue() != fdw->GetHandlerProc())
338 		{
339 			if (cbHandler->GetValue().IsEmpty())
340 				sql += wxT("ALTER FOREIGN DATA WRAPPER ") + qtIdent(name)
341 				       + wxT("\n   NO HANDLER;\n");
342 			else
343 				sql += wxT("ALTER FOREIGN DATA WRAPPER ") + qtIdent(name)
344 				       + wxT("\n   HANDLER ") + qtIdent(cbHandler->GetValue())
345 				       + wxT(";\n");
346 		}
347 
348 		if (cbValidator->GetValue() != fdw->GetValidatorProc())
349 		{
350 			if (cbValidator->GetValue().IsEmpty())
351 				sql += wxT("ALTER FOREIGN DATA WRAPPER ") + qtIdent(name)
352 				       + wxT("\n   NO VALIDATOR;\n");
353 			else
354 				sql += wxT("ALTER FOREIGN DATA WRAPPER ") + qtIdent(name)
355 				       + wxT("\n   VALIDATOR ") + qtIdent(cbValidator->GetValue())
356 				       + wxT(";\n");
357 		}
358 
359 		wxString sqloptions = GetOptionsSql();
360 		if (sqloptions.Length() > 0)
361 		{
362 			sql += wxT("ALTER FOREIGN DATA WRAPPER ") + name
363 			       + wxT(" OPTIONS (") + sqloptions + wxT(");");
364 		}
365 
366 		AppendOwnerChange(sql, wxT("FOREIGN DATA WRAPPER ") + qtIdent(name));
367 	}
368 	else
369 	{
370 		// create mode
371 		sql = wxT("CREATE FOREIGN DATA WRAPPER ") + qtIdent(name);
372 		AppendIfFilled(sql, wxT("\n   HANDLER "), qtIdent(cbHandler->GetValue()));
373 		AppendIfFilled(sql, wxT("\n   VALIDATOR "), qtIdent(cbValidator->GetValue()));
374 
375 		// check for options
376 		if (lstOptions->GetItemCount() > 0)
377 		{
378 			wxString options = wxEmptyString;
379 			for (int pos = 0 ; pos < lstOptions->GetItemCount() ; pos++)
380 			{
381 				if (options.Length() > 0)
382 					options += wxT(", ");
383 
384 				options += lstOptions->GetText(pos, 0)
385 				           + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("' ");
386 			}
387 			sql += wxT("\n  OPTIONS (") + options + wxT(")");
388 		}
389 
390 		sql += wxT(";\n");
391 		AppendOwnerNew(sql, wxT("FOREIGN DATA WRAPPER ") + qtIdent(name));
392 	}
393 
394 	sql += GetGrant(wxT("U"), wxT("FOREIGN DATA WRAPPER ") + qtIdent(name));
395 	AppendComment(sql, wxT("FOREIGN DATA WRAPPER"), 0, fdw);
396 
397 	return sql;
398 }
399 
400 
401