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