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 // pgQueryThread.h - PostgreSQL threaded query class header
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 #ifndef PGQUERYTHREAD_H
13 #define PGQUERYTHREAD_H
14 
15 #include "wx/wx.h"
16 #include "wx/event.h"
17 #include "db/pgConn.h"
18 
19 // Forward declaration
20 class pgSet;
21 class pgQueryThread;
22 class pgBatchQuery;
23 
24 // Support for the IN & INOUT parameters type
25 class pgParam : public wxObject
26 {
27 public:
28 	enum
29 	{
30 		PG_PARAM_IN       = 1,
31 		PG_PARAM_OUT      = 2,
32 		PG_PARAM_INOUT    = 3,
33 		PG_PARAM_VARIADIC = 4,
34 		PG_PARAM_TABLE    = 5
35 	};
36 
37 	// Any data
38 	//
39 	// This constructor won't call the functions - 'htonl' or 'htons'
40 	// It will be the responsibility of the caller to take care
41 	// to call 'htonl' or 'htons' depending on requirements.
42 	//
43 	// NOTE:
44 	// This data will be owned by pgParam object and will be released.
45 	pgParam(Oid _type, void *_val, int _len, short mode = PG_PARAM_IN);
46 
47 	// wxString data
48 	pgParam(Oid _type, wxString *_val, wxMBConv *_conv = NULL,
49 	        short mode = PG_PARAM_IN);
50 
51 	~pgParam();
52 
53 	// Returns 0 for text type and 1 for otherwise
54 	int   GetFormat();
55 
GetType()56 	Oid   GetType()
57 	{
58 		return m_type;
59 	}
GetMode()60 	short GetMode()
61 	{
62 		return m_mode;
63 	}
64 
65 protected:
66 	Oid    m_type;
67 	void  *m_val;
68 	int    m_len;
69 	short  m_format;
70 	// Modes are required by EnterpriseDB's callable statement
71 	short  m_mode;
72 
73 	// Do not allow copy construction and shadow-copy
74 	// to avoid ownership
75 	// Force to use an pointer
pgParam(const pgParam &)76 	pgParam(const pgParam &)
77 	{
78 		wxASSERT(0);
79 	}
80 	pgParam &operator= (const pgParam &)
81 	{
82 		wxASSERT(0);
83 		return *this;
84 	}
85 
86 	friend class pgConn;
87 	friend class pgQueryThread;
88 };
89 
90 WX_DEFINE_ARRAY_PTR(pgParam *, pgParamsArray);
91 
92 class pgBatchQuery : public wxObject
93 {
94 public:
95 	pgBatchQuery(const wxString &_query, pgParamsArray *_params = NULL,
96 	             long _eventId = -1, void *_data = NULL, bool _useCallable = false,
97 	             int _resultToRetrieve = 0)
m_query(_query)98 		: m_query(_query), m_params(_params), m_eventID(_eventId), m_data(_data),
99 		  m_useCallable(_useCallable), m_resToRetrieve(_resultToRetrieve),
100 		  m_returnCode(-1), m_resultSet(NULL), m_rowsInserted(-1), m_insertedOid(-1)
101 	{
102 		// Do not honour the empty query string
103 		wxASSERT(!_query.IsEmpty());
104 	}
105 	~pgBatchQuery();
106 
107 	bool            Release();
108 
ResultSet()109 	pgSet          *ResultSet()
110 	{
111 		return m_resultSet;
112 	}
113 
ReturnCode()114 	int             ReturnCode()
115 	{
116 		return m_returnCode;
117 	}
118 
GetMessage()119 	const wxString &GetMessage()
120 	{
121 		return m_message;
122 	}
123 
RowInserted()124 	long            RowInserted()
125 	{
126 		return m_rowsInserted;
127 	}
128 
129 	const wxString &GetErrorMessage();
130 
131 protected:
132 	wxString           m_query;         // Query
133 	pgParamsArray     *m_params;        // parameters
134 	long               m_eventID;       // Event ID
135 	void              *m_data;          // Data to be send with event
136 	bool               m_useCallable;   // Use EnterpriseDB callable statement if possible
137 	int                m_resToRetrieve; // Which result to be retrieved
138 	int                m_returnCode;    // Return code
139 	pgSet             *m_resultSet;     // Result-Set
140 	long               m_rowsInserted;  // No of rows inserted
141 	Oid                m_insertedOid;   // Inserted Oid
142 	wxString           m_message;       // Message generated during query execution
143 	pgError            m_err;           // Error
144 
145 private:
146 	// Do not allow copy construction and '=' operator (shadow copying)
147 	// to avoid ownership of parameters and result-set
148 	//
149 	// This will force this class to be used as an pointer only.
pgBatchQuery(const pgBatchQuery &)150 	pgBatchQuery(const pgBatchQuery &)
151 	{
152 		wxASSERT(0);
153 	}
154 	pgBatchQuery &operator= (const pgBatchQuery &)
155 	{
156 		wxASSERT(0);
157 		return *this;
158 	}
159 
160 	friend class pgQueryThread;
161 };
162 WX_DEFINE_ARRAY_PTR(pgBatchQuery *, pgBatchQueryArray);
163 
164 class pgQueryThread : public wxThread
165 {
166 public:
167 	// For running a single query (Used by few components)
168 	pgQueryThread(pgConn *_conn, const wxString &qry, int resultToRetrieve = -1,
169 	              wxWindow *_caller = 0, long eventId = 0, void *_data = 0);
170 
171 	// Support for multiple queries support
172 	pgQueryThread(pgConn *_conn, wxEvtHandler *_caller = NULL,
173 	              PQnoticeProcessor _processor = NULL, void *_noticeHandler = NULL);
174 
175 	~pgQueryThread();
176 
HasMultipleQueriesSupport()177 	bool HasMultipleQueriesSupport()
178 	{
179 		return m_multiQueries;
180 	}
181 
SupportCallableStatement()182 	bool SupportCallableStatement()
183 	{
184 		return m_useCallable;
185 	}
186 
187 	void SetEventOnCancellation(bool eventOnCancelled);
188 
189 	void AddQuery(
190 	    const wxString &_qry, pgParamsArray *_params = NULL,
191 	    long _eventId = 0, void *_data = NULL, bool _useCallable = false,
192 	    int _resultToRetrieve = -1);
193 
194 	virtual void *Entry();
195 	bool DataValid(int _idx = -1) const
196 	{
197 		if (_idx == -1)
198 			_idx = m_currIndex;
199 		return (_idx >= 0 && _idx > m_currIndex ? false : (m_queries[_idx]->m_resultSet != NULL));
200 	}
201 
GetConn()202 	pgConn *GetConn()
203 	{
204 		return m_conn;
205 	}
206 
207 	pgSet *DataSet(int _idx = -1)
208 	{
209 		if (_idx == -1)
210 			_idx = m_currIndex;
211 		return (_idx >= 0 && _idx > m_currIndex ? NULL : m_queries[_idx]->m_resultSet);
212 	}
213 
214 	int ReturnCode(int _idx = -1) const
215 	{
216 		if (_idx == -1)
217 			_idx = m_currIndex;
218 		return (_idx >= 0 && _idx > m_currIndex ? -1 : m_queries[_idx]->m_returnCode);
219 	}
220 
221 	long RowsInserted(int _idx = -1) const
222 	{
223 		if (_idx == -1)
224 			_idx = m_currIndex;
225 		return (_idx >= 0 && _idx > m_currIndex ? -1L : m_queries[_idx]->m_rowsInserted);
226 	}
227 
228 	Oid InsertedOid(int _idx = -1) const
229 	{
230 		if (_idx == -1)
231 			_idx = m_currIndex;
232 		return (_idx >= 0 && _idx > m_currIndex ? -1L : m_queries[_idx]->m_insertedOid);
233 	}
234 
CancelExecution()235 	inline void CancelExecution()
236 	{
237 		m_cancelled = true;
238 	}
239 
GetNumberQueries()240 	inline size_t GetNumberQueries()
241 	{
242 		return m_queries.GetCount();
243 	}
244 
QueriesExecuted()245 	size_t QueriesExecuted()
246 	{
247 		return m_currIndex + 1;
248 	}
249 
250 	wxString GetMessagesAndClear(int _idx = -1);
251 	void AppendMessage(const wxString &_str);
252 
253 	int DeleteReleasedQueries();
254 
255 	pgError GetResultError(int idx = -1);
256 
257 private:
258 	int Execute();
259 	int RaiseEvent(int _retval = 0);
260 
261 	// Queries to be executed
262 	pgBatchQueryArray  m_queries;
263 	// Current running query index
264 	int                m_currIndex;
265 	// Connection object
266 	pgConn            *m_conn;
267 	// Execution cancelled?
268 	bool               m_cancelled;
269 	// Raise events even when cancelled the execution
270 	bool               m_eventOnCancellation;
271 	// Does this thread support multiple queries
272 	bool               m_multiQueries;
273 	// Use EDB callable statement (if available and require)
274 	bool               m_useCallable;
275 	// Is executing a query
276 	bool               m_executing;
277 	// Queries are being accessed at this time
278 	wxMutex            m_queriesLock;
279 	// When one thread is accesing messages, other should not be able to access it
280 	wxCriticalSection  m_criticalSection;
281 	// Event Handler
282 	wxEvtHandler      *m_caller;
283 	// Database server notice-processor
284 	PQnoticeProcessor  m_processor;
285 	// Notice Handler
286 	void              *m_noticeHandler;
287 
288 };
289 
290 #endif
291