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 // pgaStep.cpp - PostgreSQL Agent Step
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 "schema/pgObject.h"
19 #include "schema/pgDatabase.h"
20 #include "schema/pgCollection.h"
21 #include "agent/pgaStep.h"
22 #include "agent/pgaSchedule.h"
23
pgaStep(pgCollection * _collection,const wxString & newName)24 pgaStep::pgaStep(pgCollection *_collection, const wxString &newName)
25 : pgaJobObject(_collection->GetJob(), stepFactory, newName)
26 {
27 }
28
GetTranslatedMessage(int kindOfMessage) const29 wxString pgaStep::GetTranslatedMessage(int kindOfMessage) const
30 {
31 wxString message = wxEmptyString;
32
33 switch (kindOfMessage)
34 {
35 case RETRIEVINGDETAILS:
36 message = _("Retrieving details on pgAgent step");
37 break;
38 case REFRESHINGDETAILS:
39 message = _("Refreshing pgAgent step");
40 break;
41 case PROPERTIESREPORT:
42 message = _("pgAgent step properties report");
43 break;
44 case PROPERTIES:
45 message = _("pgAgent step properties");
46 break;
47 case DDLREPORT:
48 message = _("pgAgent step DDL report");
49 break;
50 case DEPENDENCIESREPORT:
51 message = _("pgAgent step dependencies report");
52 break;
53 case DEPENDENCIES:
54 message = _("pgAgent step dependencies");
55 break;
56 case DEPENDENTSREPORT:
57 message = _("pgAgent step dependents report");
58 break;
59 case DEPENDENTS:
60 message = _("pgAgent step dependents");
61 break;
62 case DROPEXCLUDINGDEPS:
63 message = wxString::Format(_("Are you sure you wish to drop step \"%s\"?"),
64 GetFullIdentifier().c_str());
65 break;
66 case DROPTITLE:
67 message = _("Drop step?");
68 break;
69 }
70
71 if (!message.IsEmpty() && !(kindOfMessage == DROPEXCLUDINGDEPS || kindOfMessage == DROPTITLE))
72 message += wxT(" - ") + GetName();
73
74 return message;
75 }
76
IsUpToDate()77 bool pgaStep::IsUpToDate()
78 {
79 wxString sql = wxT("SELECT xmin FROM pgagent.pga_jobstep WHERE jstid = ") + NumToStr(GetRecId());
80 if (!GetConnection() || GetConnection()->ExecuteScalar(sql) != NumToStr(GetXid()))
81 return false;
82 else
83 return true;
84 }
85
DropObject(wxFrame * frame,ctlTree * browser,bool cascaded)86 bool pgaStep::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
87 {
88 return GetConnection()->ExecuteVoid(wxT("DELETE FROM pgagent.pga_jobstep WHERE jstid=") + NumToStr(GetRecId()));
89 }
90
91
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)92 void pgaStep::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
93 {
94 if (!expandedKids)
95 {
96 expandedKids = true;
97 }
98
99 if (properties)
100 {
101 CreateListColumns(properties);
102
103 properties->AppendItem(_("Name"), GetName());
104 properties->AppendItem(_("ID"), GetRecId());
105 properties->AppendYesNoItem(_("Enabled"), GetEnabled());
106 properties->AppendItem(_("Kind"), GetKind());
107 if (GetConnStr().IsEmpty())
108 properties->AppendItem(_("Database"), GetDbname());
109 else
110 properties->AppendItem(_("Connection String"), GetConnStr());
111 properties->AppendItem(_("Code"), GetCode());
112 properties->AppendItem(_("On error"), GetOnError());
113
114 properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
115 }
116 }
117
118
119
Refresh(ctlTree * browser,const wxTreeItemId item)120 pgObject *pgaStep::Refresh(ctlTree *browser, const wxTreeItemId item)
121 {
122 pgObject *step = 0;
123
124 pgCollection *coll = browser->GetParentCollection(item);
125 if (coll)
126 step = stepFactory.CreateObjects(coll, 0, wxT("\n AND jstid=") + NumToStr(GetRecId()));
127
128 return step;
129 }
130
131
132
CreateObjects(pgCollection * collection,ctlTree * browser,const wxString & restriction)133 pgObject *pgaStepFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
134 {
135 pgaStep *step = 0;
136
137 pgSet *steps = collection->GetConnection()->ExecuteSet(
138 wxT("SELECT xmin, * FROM pgagent.pga_jobstep\n")
139 wxT(" WHERE jstjobid=") + NumToStr(collection->GetJob()->GetRecId()) + wxT("\n")
140 + restriction +
141 wxT(" ORDER BY jstname"));
142
143 if (steps)
144 {
145 while (!steps->Eof())
146 {
147
148 step = new pgaStep(collection, steps->GetVal(wxT("jstname")));
149 step->iSetRecId(steps->GetLong(wxT("jstid")));
150 step->iSetXid(steps->GetOid(wxT("xmin")));
151 step->iSetDbname(steps->GetVal(wxT("jstdbname")));
152 if (steps->HasColumn(wxT("jstconnstr")))
153 step->iSetConnStr(steps->GetVal(wxT("jstconnstr")));
154 step->iSetCode(steps->GetVal(wxT("jstcode")));
155 step->iSetEnabled(steps->GetBool(wxT("jstenabled")));
156
157 wxChar kindc = *steps->GetVal(wxT("jstkind")).c_str();
158 wxString kinds;
159 switch (kindc)
160 {
161 case 'b':
162 kinds = _("Batch");
163 break;
164 case 's':
165 kinds = wxT("SQL");
166 break;
167 }
168 step->iSetKindChar(kindc);
169 step->iSetKind(kinds);
170
171 wxChar onerrc = *steps->GetVal(wxT("jstonerror")).c_str();
172 wxString onerrs;
173 switch (onerrc)
174 {
175 case 's':
176 onerrs = _("Succeed");
177 break;
178 case 'f':
179 onerrs = _("Fail");
180 break;
181 case 'i':
182 onerrs = _("Ignore");
183 break;
184
185
186 }
187
188 step->iSetOnErrorChar(onerrc);
189 step->iSetOnError(onerrs);
190 step->iSetComment(steps->GetVal(wxT("jstdesc")));
191
192
193 if (browser)
194 {
195 browser->AppendObject(collection, step);
196 steps->MoveNext();
197 }
198 else
199 break;
200 }
201
202 delete steps;
203 }
204 return step;
205 }
206
207
ShowStatistics(frmMain * form,ctlListView * statistics)208 void pgaStep::ShowStatistics(frmMain *form, ctlListView *statistics)
209 {
210 wxString sql =
211 wxT("SELECT jsljlgid")
212 wxT(", jslstatus")
213 wxT(", jslresult")
214 wxT(", jslstart")
215 wxT(", jslduration")
216 wxT(", (jslstart + jslduration) AS endtime")
217 wxT(", jsloutput")
218 wxT(" FROM pgagent.pga_jobsteplog\n")
219 wxT(" WHERE jsljstid = ") + NumToStr(GetRecId()) +
220 wxT(" ORDER BY jslstart DESC")
221 wxT(" LIMIT ") + NumToStr(settings->GetMaxRows());
222
223 if (statistics)
224 {
225 wxLogInfo(wxT("Displaying statistics for job %s"), GetFullIdentifier().c_str());
226
227 // Add the statistics view columns
228 statistics->ClearAll();
229 statistics->AddColumn(_("Run"), 50);
230 statistics->AddColumn(_("Status"), 60);
231 statistics->AddColumn(_("Result"), 60);
232 statistics->AddColumn(_("Start time"), 95);
233 statistics->AddColumn(_("End time"), 95);
234 statistics->AddColumn(_("Duration"), 70);
235 statistics->AddColumn(_("Output"), 200);
236
237 pgSet *stats = GetConnection()->ExecuteSet(sql);
238 wxString status;
239 wxDateTime startTime;
240 wxDateTime endTime;
241
242 if (stats)
243 {
244 while (!stats->Eof())
245 {
246 if (stats->GetVal(1) == wxT("r"))
247 status = _("Running");
248 else if (stats->GetVal(1) == wxT("s"))
249 status = _("Successful");
250 else if (stats->GetVal(1) == wxT("f"))
251 status = _("Failed");
252 else if (stats->GetVal(1) == wxT("i"))
253 status = _("Ignored");
254 else if (stats->GetVal(1) == wxT("d"))
255 status = _("Aborted");
256 else
257 status = _("Unknown");
258
259 startTime.ParseDateTime(stats->GetVal(3));
260 endTime.ParseDateTime(stats->GetVal(5));
261
262 long pos = statistics->AppendItem(stats->GetVal(0), status, stats->GetVal(2));
263 statistics->SetItem(pos, 3, startTime.Format());
264 if (stats->GetVal(5).Length() > 0)
265 statistics->SetItem(pos, 4, endTime.Format());
266 statistics->SetItem(pos, 5, stats->GetVal(4));
267 statistics->SetItem(pos, 6, stats->GetVal(6));
268
269 stats->MoveNext();
270 }
271 delete stats;
272 }
273 }
274 }
275
276
277 /////////////////////////////
278
279
pgaStepCollection(pgaFactory * factory,pgaJob * job)280 pgaStepCollection::pgaStepCollection(pgaFactory *factory, pgaJob *job)
281 : pgaJobObjCollection(factory, job)
282 {
283 }
284
285
GetTranslatedMessage(int kindOfMessage) const286 wxString pgaStepCollection::GetTranslatedMessage(int kindOfMessage) const
287 {
288 wxString message = wxEmptyString;
289
290 switch (kindOfMessage)
291 {
292 case RETRIEVINGDETAILS:
293 message = _("Retrieving details on pgAgent steps");
294 break;
295 case REFRESHINGDETAILS:
296 message = _("Refreshing pgAgent steps");
297 break;
298 case OBJECTSLISTREPORT:
299 message = _("pgAgent steps list report");
300 break;
301 }
302
303 return message;
304 }
305
306
307 /////////////////////////////
308
309
310 #include "images/step.pngc"
311 #include "images/steps.pngc"
312
pgaStepFactory()313 pgaStepFactory::pgaStepFactory()
314 : pgaJobObjFactory(__("Step"), __("New Step"), __("Create a new Step."), step_png_img)
315 {
316 metaType = PGM_STEP;
317 }
318
319
CreateCollection(pgObject * obj)320 pgCollection *pgaStepFactory::CreateCollection(pgObject *obj)
321 {
322 return new pgaStepCollection(GetCollectionFactory(), (pgaJob *)obj);
323 }
324
325
326 pgaStepFactory stepFactory;
327 static pgaCollectionFactory cf(&stepFactory, __("Steps"), steps_png_img);
328