1 /***********************************************************************************************************************************
2 Pq Test Harness
3 
4 Scripted testing for PostgreSQL libpq so exact results can be returned for unit testing.  See PostgreSQL client unit tests for
5 usage examples.
6 ***********************************************************************************************************************************/
7 #ifndef TEST_COMMON_HARNESS_PQ_H
8 #define TEST_COMMON_HARNESS_PQ_H
9 
10 #ifndef HARNESS_PQ_REAL
11 
12 #include <libpq-fe.h>
13 
14 #include "common/macro.h"
15 #include "common/time.h"
16 #include "version.h"
17 
18 /***********************************************************************************************************************************
19 Function constants
20 ***********************************************************************************************************************************/
21 #define HRNPQ_CANCEL                                                "PQcancel"
22 #define HRNPQ_CLEAR                                                 "PQclear"
23 #define HRNPQ_CONNECTDB                                             "PQconnectdb"
24 #define HRNPQ_CONSUMEINPUT                                          "PQconsumeInput"
25 #define HRNPQ_ERRORMESSAGE                                          "PQerrorMessage"
26 #define HRNPQ_FINISH                                                "PQfinish"
27 #define HRNPQ_FREECANCEL                                            "PQfreeCancel"
28 #define HRNPQ_FTYPE                                                 "PQftype"
29 #define HRNPQ_GETCANCEL                                             "PQgetCancel"
30 #define HRNPQ_GETISNULL                                             "PQgetisnull"
31 #define HRNPQ_GETRESULT                                             "PQgetResult"
32 #define HRNPQ_GETVALUE                                              "PQgetvalue"
33 #define HRNPQ_ISBUSY                                                "PQisbusy"
34 #define HRNPQ_NFIELDS                                               "PQnfields"
35 #define HRNPQ_NTUPLES                                               "PQntuples"
36 #define HRNPQ_RESULTERRORMESSAGE                                    "PQresultErrorMessage"
37 #define HRNPQ_RESULTSTATUS                                          "PQresultStatus"
38 #define HRNPQ_SENDQUERY                                             "PQsendQuery"
39 #define HRNPQ_STATUS                                                "PQstatus"
40 
41 /***********************************************************************************************************************************
42 Macros for defining groups of functions that implement various queries and commands
43 ***********************************************************************************************************************************/
44 #define HRNPQ_MACRO_OPEN(sessionParam, connectParam)                                                                               \
45     {.session = sessionParam, .function = HRNPQ_CONNECTDB, .param = "[\"" connectParam "\"]"},                                     \
46     {.session = sessionParam, .function = HRNPQ_STATUS, .resultInt = CONNECTION_OK}
47 
48 #define HRNPQ_MACRO_SET_CLIENT_ENCODING(sessionParam)                                                                              \
49     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = "[\"set client_encoding = 'UTF8'\"]", .resultInt = 1},         \
50     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
51     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
52     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
53     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_COMMAND_OK},                                      \
54     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
55     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
56 
57 #define HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam)                                                                                  \
58     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = "[\"set search_path = 'pg_catalog'\"]", .resultInt = 1},       \
59     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
60     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
61     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
62     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_COMMAND_OK},                                      \
63     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
64     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
65 
66 #define HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, versionParam, pgPathParam, archiveMode, archiveCommand)                           \
67     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param =                                                                \
68         "[\"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4,"                          \
69             " (select setting from pg_catalog.pg_settings where name = 'data_directory')::text,"                                   \
70             " (select setting from pg_catalog.pg_settings where name = 'archive_mode')::text,"                                     \
71             " (select setting from pg_catalog.pg_settings where name = 'archive_command')::text\"]",                               \
72         .resultInt = 1},                                                                                                           \
73     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
74     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
75     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
76     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
77     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
78     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 4},                                                          \
79     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT},                               \
80     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
81     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_TEXT},                              \
82     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[3]", .resultInt = HRNPQ_TYPE_TEXT},                              \
83     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(versionParam)},                   \
84     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = pgPathParam},                               \
85     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = archiveMode == NULL ? "on"                  \
86         : archiveMode},                                                                                                            \
87     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,3]", .resultZ = archiveCommand == NULL ? PROJECT_BIN        \
88         : archiveCommand},                                                                                                         \
89     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
90     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
91 
92 #define HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam)                                                                             \
93     {.session = sessionParam, .function = HRNPQ_SENDQUERY,                                                                         \
94         .param = strZ(strNewFmt("[\"set application_name = '" PROJECT_NAME " [%s]'\"]", cfgCommandName())),                        \
95         .resultInt = 1},                                                                                                           \
96     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
97     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
98     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
99     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_COMMAND_OK},                                      \
100     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
101     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
102 
103 #define HRNPQ_MACRO_SET_MAX_PARALLEL_WORKERS_PER_GATHER(sessionParam)                                                              \
104     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = "[\"set max_parallel_workers_per_gather = 0\"]",               \
105         .resultInt = 1},                                                                                                           \
106     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
107     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
108     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
109     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_COMMAND_OK},                                      \
110     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
111     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
112 
113 #define HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam)                                                                   \
114     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = "[\"select pg_catalog.pg_is_in_recovery()\"]", .resultInt = 1},\
115     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
116     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
117     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
118     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
119     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
120     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
121     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_BOOL},                              \
122     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(standbyParam)},                   \
123     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
124     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
125 
126 #define HRNPQ_MACRO_CREATE_RESTORE_POINT(sessionParam, lsnParam)                                                                   \
127     {.session = sessionParam,                                                                                                      \
128         .function = HRNPQ_SENDQUERY, .param = "[\"select pg_catalog.pg_create_restore_point('pgBackRest Archive Check')::text\"]", \
129         .resultInt = 1},                                                                                                           \
130     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
131     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
132     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
133     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
134     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
135     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
136     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
137     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
138     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
139     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
140 
141 #define HRNPQ_MACRO_WAL_SWITCH(sessionParam, walNameParam, walFileNameParam)                                                       \
142     {.session = sessionParam, .function = HRNPQ_SENDQUERY,                                                                         \
143         .param = "[\"select pg_catalog.pg_" walNameParam "file_name(pg_catalog.pg_switch_" walNameParam "())::text\"]",            \
144         .resultInt = 1},                                                                                                           \
145     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
146     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
147     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
148     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
149     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
150     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
151     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
152     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = walFileNameParam},                          \
153     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
154     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
155 
156 #define HRNPQ_MACRO_TIME_QUERY(sessionParam, timeParam)                                                                            \
157     {.session = sessionParam,                                                                                                      \
158         .function = HRNPQ_SENDQUERY, .param = "[\"select (extract(epoch from clock_timestamp()) * 1000)::bigint\"]",               \
159         .resultInt = 1},                                                                                                           \
160     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
161     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
162     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
163     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
164     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
165     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
166     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT},                               \
167     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]",                                                        \
168         .resultZ = strZ(strNewFmt("%" PRId64, (int64_t)(timeParam)))},                                                             \
169     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
170     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
171 
172 #define HRNPQ_MACRO_ADVISORY_LOCK(sessionParam, lockAcquiredParam)                                                                 \
173     {.session = sessionParam,                                                                                                      \
174         .function = HRNPQ_SENDQUERY, .param = "[\"select pg_catalog.pg_try_advisory_lock(12340078987004321)::bool\"]",             \
175         .resultInt = 1},                                                                                                           \
176     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
177     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
178     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
179     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
180     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
181     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
182     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_BOOL},                              \
183     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = cvtBoolToConstZ(lockAcquiredParam)},        \
184     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
185     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
186 
187 #define HRNPQ_MACRO_IS_IN_BACKUP(sessionParam, inBackupParam)                                                                      \
188     {.session = sessionParam,                                                                                                      \
189         .function = HRNPQ_SENDQUERY, .param = "[\"select pg_catalog.pg_is_in_backup()::bool\"]",                                   \
190         .resultInt = 1},                                                                                                           \
191     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
192     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
193     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
194     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
195     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
196     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 1},                                                          \
197     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_BOOL},                              \
198     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = cvtBoolToConstZ(inBackupParam)},            \
199     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
200     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
201 
202 #define HRNPQ_MACRO_START_BACKUP_83(sessionParam, lsnParam, walSegmentNameParam)                                                   \
203     {.session = sessionParam,                                                                                                      \
204         .function = HRNPQ_SENDQUERY,                                                                                               \
205         .param =                                                                                                                   \
206             "[\"select lsn::text as lsn,\\n"                                                                                       \
207             "       pg_catalog.pg_xlogfile_name(lsn)::text as wal_segment_name\\n"                                                 \
208             "  from pg_catalog.pg_start_backup('pgBackRest backup started at ' || current_timestamp) as lsn\"]",                   \
209         .resultInt = 1},                                                                                                           \
210     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
211     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
212     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
213     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
214     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
215     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
216     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
217     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
218     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
219     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
220     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
221     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
222 
223 #define HRNPQ_MACRO_START_BACKUP_84_95(sessionParam, startFastParam, lsnParam, walSegmentNameParam)                                \
224     {.session = sessionParam,                                                                                                      \
225         .function = HRNPQ_SENDQUERY,                                                                                               \
226         .param = strZ(strNewFmt(                                                                                                   \
227             "[\"select lsn::text as lsn,\\n"                                                                                       \
228             "       pg_catalog.pg_xlogfile_name(lsn)::text as wal_segment_name\\n"                                                 \
229             "  from pg_catalog.pg_start_backup('pgBackRest backup started at ' || current_timestamp, %s) as lsn\"]",               \
230             cvtBoolToConstZ(startFastParam))),                                                                                     \
231         .resultInt = 1},                                                                                                           \
232     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
233     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
234     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
235     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
236     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
237     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
238     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
239     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
240     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
241     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
242     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
243     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
244 
245 #define HRNPQ_MACRO_START_BACKUP_96(sessionParam, startFastParam, lsnParam, walSegmentNameParam)                                   \
246     {.session = sessionParam,                                                                                                      \
247         .function = HRNPQ_SENDQUERY,                                                                                               \
248         .param = strZ(strNewFmt(                                                                                                   \
249             "[\"select lsn::text as lsn,\\n"                                                                                       \
250             "       pg_catalog.pg_xlogfile_name(lsn)::text as wal_segment_name\\n"                                                 \
251             "  from pg_catalog.pg_start_backup('pgBackRest backup started at ' || current_timestamp, %s, false) as lsn\"]",        \
252             cvtBoolToConstZ(startFastParam))),                                                                                     \
253         .resultInt = 1},                                                                                                           \
254     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
255     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
256     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
257     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
258     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
259     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
260     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
261     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
262     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
263     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
264     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
265     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
266 
267 #define HRNPQ_MACRO_START_BACKUP_GE_10(sessionParam, startFastParam, lsnParam, walSegmentNameParam)                                \
268     {.session = sessionParam,                                                                                                      \
269         .function = HRNPQ_SENDQUERY,                                                                                               \
270         .param = strZ(strNewFmt(                                                                                                   \
271             "[\"select lsn::text as lsn,\\n"                                                                                       \
272             "       pg_catalog.pg_walfile_name(lsn)::text as wal_segment_name\\n"                                                  \
273             "  from pg_catalog.pg_start_backup('pgBackRest backup started at ' || current_timestamp, %s, false) as lsn\"]",        \
274             cvtBoolToConstZ(startFastParam))),                                                                                     \
275         .resultInt = 1},                                                                                                           \
276     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
277     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
278     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
279     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
280     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
281     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
282     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
283     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
284     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
285     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
286     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
287     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
288 
289 #define HRNPQ_MACRO_STOP_BACKUP_LE_95(sessionParam, lsnParam, walSegmentNameParam)                                                 \
290     {.session = sessionParam,                                                                                                      \
291         .function = HRNPQ_SENDQUERY,                                                                                               \
292         .param =                                                                                                                   \
293             "[\"select lsn::text as lsn,\\n"                                                                                       \
294             "       pg_catalog.pg_xlogfile_name(lsn)::text as wal_segment_name\\n"                                                 \
295             "  from pg_catalog.pg_stop_backup() as lsn\"]",                                                                               \
296         .resultInt = 1},                                                                                                           \
297     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
298     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
299     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
300     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
301     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
302     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
303     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
304     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
305     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
306     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
307     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
308     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
309 
310 #define HRNPQ_MACRO_STOP_BACKUP_96(sessionParam, lsnParam, walSegmentNameParam, tablespaceMapParam)                                \
311     {.session = sessionParam,                                                                                                      \
312         .function = HRNPQ_SENDQUERY,                                                                                               \
313         .param =                                                                                                                   \
314             "[\"select lsn::text as lsn,\\n"                                                                                       \
315             "       pg_catalog.pg_xlogfile_name(lsn)::text as wal_segment_name,\\n"                                                \
316             "       labelfile::text as backuplabel_file,\\n"                                                                       \
317             "       spcmapfile::text as tablespacemap_file\\n"                                                                     \
318             "  from pg_catalog.pg_stop_backup(false)\"]",                                                                          \
319         .resultInt = 1},                                                                                                           \
320     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
321     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
322     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
323     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
324     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
325     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 4},                                                          \
326     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
327     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
328     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_TEXT},                              \
329     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[3]", .resultInt = HRNPQ_TYPE_TEXT},                              \
330     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
331     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
332     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = "BACKUP_LABEL_DATA"},                       \
333     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,3]",                                                        \
334         .resultZ = tablespaceMapParam ? "TABLESPACE_MAP_DATA" : "\n"},                                                             \
335     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
336     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
337 
338 #define HRNPQ_MACRO_STOP_BACKUP_GE_10(sessionParam, lsnParam, walSegmentNameParam, tablespaceMapParam)                             \
339     {.session = sessionParam,                                                                                                      \
340         .function = HRNPQ_SENDQUERY,                                                                                               \
341         .param =                                                                                                                   \
342             "[\"select lsn::text as lsn,\\n"                                                                                       \
343             "       pg_catalog.pg_walfile_name(lsn)::text as wal_segment_name,\\n"                                                 \
344             "       labelfile::text as backuplabel_file,\\n"                                                                       \
345             "       spcmapfile::text as tablespacemap_file\\n"                                                                     \
346             "  from pg_catalog.pg_stop_backup(false, false)\"]",                                                                   \
347         .resultInt = 1},                                                                                                           \
348     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
349     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
350     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
351     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
352     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
353     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 4},                                                          \
354     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
355     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
356     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_TEXT},                              \
357     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[3]", .resultInt = HRNPQ_TYPE_TEXT},                              \
358     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = lsnParam},                                  \
359     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = walSegmentNameParam},                       \
360     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = "BACKUP_LABEL_DATA"},                       \
361     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,3]",                                                        \
362         .resultZ = tablespaceMapParam ? "TABLESPACE_MAP_DATA" : "\n"},                                                             \
363     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
364     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
365 
366 #define HRNPQ_MACRO_DATABASE_LIST_1(sessionParam, databaseNameParam)                                                               \
367     {.session = sessionParam,                                                                                                      \
368         .function = HRNPQ_SENDQUERY,                                                                                               \
369         .param = "[\"select oid::oid, datname::text, datlastsysoid::oid from pg_catalog.pg_database\"]",                           \
370         .resultInt = 1},                                                                                                           \
371     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
372     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
373     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
374     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
375     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
376     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 3},                                                          \
377     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT},                               \
378     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
379     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_INT},                               \
380     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(16384)},                          \
381     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = databaseNameParam},                         \
382     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = STRINGIFY(13777)},                          \
383     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
384     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
385 
386 #define HRNPQ_MACRO_TABLESPACE_LIST_0(sessionParam)                                                                                \
387     {.session = sessionParam,                                                                                                      \
388         .function = HRNPQ_SENDQUERY, .param = "[\"select oid::oid, spcname::text from pg_catalog.pg_tablespace\"]",                \
389         .resultInt = 1},                                                                                                           \
390     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
391     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
392     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
393     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
394     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 0},                                                          \
395     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
396     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT},                               \
397     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
398     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
399     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
400 
401 #define HRNPQ_MACRO_TABLESPACE_LIST_1(sessionParam, id1Param, name1Param)                                                          \
402     {.session = sessionParam,                                                                                                      \
403         .function = HRNPQ_SENDQUERY, .param = "[\"select oid::oid, spcname::text from pg_catalog.pg_tablespace\"]",                \
404         .resultInt = 1},                                                                                                           \
405     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
406     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
407     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
408     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
409     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
410     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
411     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT},                               \
412     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
413     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = strZ(strNewFmt("%d", id1Param))},           \
414     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = name1Param},                                \
415     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
416     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
417 
418 #define HRNPQ_MACRO_CHECKPOINT(sessionParam)                                                                                       \
419     {.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = "[\"checkpoint\"]", .resultInt = 1},                           \
420     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
421     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
422     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
423     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_COMMAND_OK},                                      \
424     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
425     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
426 
427 #define HRNPQ_MACRO_REPLAY_TARGET_REACHED(                                                                                         \
428     sessionParam, walNameParam, lsnNameParam, targetLsnParam, targetReachedParam, replayLsnParam)                                  \
429     {.session = sessionParam,                                                                                                      \
430         .function = HRNPQ_SENDQUERY,                                                                                               \
431         .param =  strZ(strNewFmt(                                                                                                  \
432             "[\"select replayLsn::text,\\n"                                                                                        \
433             "       (replayLsn > '%s')::bool as targetReached\\n"                                                                  \
434             "  from pg_catalog.pg_last_" walNameParam "_replay_" lsnNameParam "() as replayLsn\"]", targetLsnParam)),              \
435         .resultInt = 1},                                                                                                           \
436     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
437     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
438     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
439     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
440     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
441     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
442     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_TEXT},                              \
443     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_BOOL},                              \
444     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = replayLsnParam},                            \
445     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = cvtBoolToConstZ(targetReachedParam)},       \
446     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
447     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
448 
449 #define HRNPQ_MACRO_REPLAY_TARGET_REACHED_LE_96(sessionParam, targetLsnParam, targetReachedParam, reachedLsnParam)                 \
450     HRNPQ_MACRO_REPLAY_TARGET_REACHED(sessionParam, "xlog", "location", targetLsnParam, targetReachedParam, reachedLsnParam)
451 
452 #define HRNPQ_MACRO_REPLAY_TARGET_REACHED_GE_10(sessionParam, targetLsnParam, targetReachedParam, reachedLsnParam)                 \
453     HRNPQ_MACRO_REPLAY_TARGET_REACHED(sessionParam, "wal", "lsn", targetLsnParam, targetReachedParam, reachedLsnParam)
454 
455 #define HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED(                                                                                     \
456     sessionParam, lsnNameParam, targetLsnParam, targetReachedParam, checkpointLsnParam, sleepParam)                                \
457     {.session = sessionParam,                                                                                                      \
458         .function = HRNPQ_SENDQUERY,                                                                                               \
459         .param = strZ(strNewFmt(                                                                                                   \
460             "[\"select (checkpoint_" lsnNameParam " > '%s')::bool as targetReached,\\n"                                            \
461             "       checkpoint_" lsnNameParam "::text as checkpointLsn\\n"                                                         \
462             "  from pg_catalog.pg_control_checkpoint()\"]", targetLsnParam)),                                                      \
463         .resultInt = 1, .sleep = sleepParam},                                                                                      \
464     {.session = sessionParam, .function = HRNPQ_CONSUMEINPUT},                                                                     \
465     {.session = sessionParam, .function = HRNPQ_ISBUSY},                                                                           \
466     {.session = sessionParam, .function = HRNPQ_GETRESULT},                                                                        \
467     {.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK},                                       \
468     {.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1},                                                          \
469     {.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2},                                                          \
470     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_BOOL},                              \
471     {.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT},                              \
472     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = cvtBoolToConstZ(targetReachedParam)},       \
473     {.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = checkpointLsnParam},                        \
474     {.session = sessionParam, .function = HRNPQ_CLEAR},                                                                            \
475     {.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
476 
477 #define HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED_96(sessionParam, targetLsnParam, targetReachedParam, checkpointLsnParam, sleepParam) \
478     HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED(                                                                                         \
479         sessionParam, "location", targetLsnParam, targetReachedParam, checkpointLsnParam, sleepParam)
480 
481 #define HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED_GE_10(                                                                               \
482     sessionParam, targetLsnParam, targetReachedParam, checkpointLsnParam, sleepParam)                                              \
483     HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED(sessionParam, "lsn", targetLsnParam, targetReachedParam, checkpointLsnParam, sleepParam)
484 
485 #define HRNPQ_MACRO_REPLAY_WAIT_LE_95(sessionParam, targetLsnParam)                                                                \
486     HRNPQ_MACRO_REPLAY_TARGET_REACHED_LE_96(sessionParam, targetLsnParam, true, "X/X"),                                            \
487     HRNPQ_MACRO_CHECKPOINT(sessionParam)
488 
489 #define HRNPQ_MACRO_REPLAY_WAIT_96(sessionParam, targetLsnParam)                                                                   \
490     HRNPQ_MACRO_REPLAY_TARGET_REACHED_LE_96(sessionParam, targetLsnParam, true, "X/X"),                                            \
491     HRNPQ_MACRO_CHECKPOINT(sessionParam),                                                                                          \
492     HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED_96(sessionParam, targetLsnParam, true, "X/X", 0)
493 
494 #define HRNPQ_MACRO_REPLAY_WAIT_GE_10(sessionParam, targetLsnParam)                                                                \
495     HRNPQ_MACRO_REPLAY_TARGET_REACHED_GE_10(sessionParam, targetLsnParam, true, "X/X"),                                            \
496     HRNPQ_MACRO_CHECKPOINT(sessionParam),                                                                                          \
497     HRNPQ_MACRO_CHECKPOINT_TARGET_REACHED_GE_10(sessionParam, targetLsnParam, true, "X/X", 0)
498 
499 #define HRNPQ_MACRO_CLOSE(sessionParam)                                                                                            \
500     {.session = sessionParam, .function = HRNPQ_FINISH}
501 
502 #define HRNPQ_MACRO_DONE()                                                                                                         \
503     {.function = NULL}
504 
505 /***********************************************************************************************************************************
506 Macros to simplify dbOpen() for specific database versions
507 ***********************************************************************************************************************************/
508 #define HRNPQ_MACRO_OPEN_LE_91(sessionParam, connectParam, pgVersion, pgPathParam, archiveMode, archiveCommand)                    \
509     HRNPQ_MACRO_OPEN(sessionParam, connectParam),                                                                                  \
510     HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam),                                                                                     \
511     HRNPQ_MACRO_SET_CLIENT_ENCODING(sessionParam),                                                                                 \
512     HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, pgVersion, pgPathParam, archiveMode, archiveCommand)
513 
514 #define HRNPQ_MACRO_OPEN_GE_92(sessionParam, connectParam, pgVersion, pgPathParam, standbyParam, archiveMode, archiveCommand)      \
515     HRNPQ_MACRO_OPEN(sessionParam, connectParam),                                                                                  \
516     HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam),                                                                                     \
517     HRNPQ_MACRO_SET_CLIENT_ENCODING(sessionParam),                                                                                 \
518     HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, pgVersion, pgPathParam, archiveMode, archiveCommand),                                 \
519     HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam),                                                                                \
520     HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam)
521 
522 #define HRNPQ_MACRO_OPEN_GE_96(sessionParam, connectParam, pgVersion, pgPathParam, standbyParam, archiveMode, archiveCommand)      \
523     HRNPQ_MACRO_OPEN(sessionParam, connectParam),                                                                                  \
524     HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam),                                                                                     \
525     HRNPQ_MACRO_SET_CLIENT_ENCODING(sessionParam),                                                                                 \
526     HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, pgVersion, pgPathParam, archiveMode, archiveCommand),                                 \
527     HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam),                                                                                \
528     HRNPQ_MACRO_SET_MAX_PARALLEL_WORKERS_PER_GATHER(sessionParam),                                                                 \
529     HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam)
530 
531 /***********************************************************************************************************************************
532 Data type constants
533 ***********************************************************************************************************************************/
534 #define HRNPQ_TYPE_BOOL                                             16
535 #define HRNPQ_TYPE_INT                                              20
536 #define HRNPQ_TYPE_TEXT                                             25
537 
538 /***********************************************************************************************************************************
539 Structure for scripting pq responses
540 ***********************************************************************************************************************************/
541 typedef struct HarnessPq
542 {
543     unsigned int session;                                           // Session number when multiple sessions are run concurrently
544     const char *function;                                           // Function call expected
545     const char *param;                                              // Params expected by the function for verification
546     int resultInt;                                                  // Int result value
547     const char *resultZ;                                            // Zero-terminated result value
548     bool resultNull;                                                // Return null from function that normally returns a struct ptr
549     TimeMSec sleep;                                                 // Sleep specified milliseconds before returning from function
550 } HarnessPq;
551 
552 /***********************************************************************************************************************************
553 Functions
554 ***********************************************************************************************************************************/
555 void harnessPqScriptSet(HarnessPq *harnessPqScriptParam);
556 
557 // Are we strict about requiring PQfinish()?  Strict is a good idea for low-level testing of Pq code but is a nuissance for
558 // higher-level testing since it can mask other errors.  When not strict, PGfinish() is allowed at any time and does not need to be
559 // scripted.
560 void harnessPqScriptStrictSet(bool strict);
561 
562 #endif // HARNESS_PQ_REAL
563 
564 #endif
565