github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/acceptance/testdata/c/test.c (about) 1 #include <libpq-fe.h> 2 #include <libpqtypes.h> 3 #include <limits.h> 4 #include <string.h> 5 #include <sys/param.h> 6 7 int intervalEqual(PGinterval left, PGinterval right) { 8 if (left.years != right.years) { 9 return 0; 10 } 11 if (left.mons != right.mons) { 12 return 0; 13 } 14 if (left.days != right.days) { 15 return 0; 16 } 17 if (left.hours != right.hours) { 18 return 0; 19 } 20 if (left.mins != right.mins) { 21 return 0; 22 } 23 if (left.secs != right.secs) { 24 return 0; 25 } 26 if (left.usecs != right.usecs) { 27 return 0; 28 } 29 return 1; 30 } 31 32 void intervalPrint(PGinterval interval) { 33 fprintf(stderr, "years=%d\n", interval.years); 34 fprintf(stderr, "mons=%d\n", interval.mons); 35 fprintf(stderr, "days=%d\n", interval.days); 36 fprintf(stderr, "hours=%d\n", interval.hours); 37 fprintf(stderr, "mins=%d\n", interval.mins); 38 fprintf(stderr, "secs=%d\n", interval.secs); 39 fprintf(stderr, "usecs=%d\n", interval.usecs); 40 } 41 42 int dateEqual(PGdate left, PGdate right) { 43 // Only check the fields we explicitly set. The uninitialized fields for our 44 // expected result will have non-deterministic values, and those same fields 45 // may be populated in the actual result by libpqtypes after decoding the 46 // database query's output. 47 if (left.isbc != right.isbc) { 48 return 0; 49 } 50 if (left.year != right.year) { 51 return 0; 52 } 53 if (left.mon != right.mon) { 54 return 0; 55 } 56 if (left.mday != right.mday) { 57 return 0; 58 } 59 return 1; 60 } 61 62 void datePrint(PGdate date) { 63 fprintf(stderr, "isbc=%d\n", date.isbc); 64 fprintf(stderr, "year=%d\n", date.year); 65 fprintf(stderr, "mon=%d\n", date.mon); 66 fprintf(stderr, "mday=%d\n", date.mday); 67 } 68 69 int timeEqual(PGtime left, PGtime right) { 70 // Only check the fields we explicitly set. See comment on dateEqual. 71 if (left.hour != right.hour) { 72 return 0; 73 } 74 if (left.min != right.min) { 75 return 0; 76 } 77 if (left.sec != right.sec) { 78 return 0; 79 } 80 if (left.usec != right.usec) { 81 return 0; 82 } 83 if (left.withtz != right.withtz) { 84 return 0; 85 } 86 if (left.gmtoff != right.gmtoff) { 87 return 0; 88 } 89 return 1; 90 } 91 92 void timePrint(PGtime time) { 93 fprintf(stderr, "hour=%d\n", time.hour); 94 fprintf(stderr, "min=%d\n", time.min); 95 fprintf(stderr, "sec=%d\n", time.sec); 96 fprintf(stderr, "usec=%d\n", time.usec); 97 fprintf(stderr, "withtz=%d\n", time.withtz); 98 fprintf(stderr, "gmtoff=%d\n", time.gmtoff); 99 } 100 101 int timestampEqual(PGtimestamp left, PGtimestamp right) { 102 if (left.epoch != right.epoch) { 103 return 0; 104 } 105 if (!dateEqual(left.date, right.date)) { 106 return 0; 107 } 108 if (!timeEqual(left.time, right.time)) { 109 return 0; 110 } 111 return 1; 112 } 113 114 void timestampPrint(PGtimestamp ts) { 115 fprintf(stderr, "epoch=%lld\n", ts.epoch); 116 fprintf(stderr, "date:\n"); 117 datePrint(ts.date); 118 fprintf(stderr, "time:\n"); 119 timePrint(ts.time); 120 } 121 122 int main(int argc, char *argv[]) { 123 if (argc != 2) { 124 fprintf(stderr, "usage: %s QUERY\n", argv[0]); 125 return 1; 126 } 127 char *query = argv[1]; 128 129 PGconn *conn = PQconnectdb(""); 130 if (PQstatus(conn) != CONNECTION_OK) { 131 fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); 132 return 1; 133 } 134 135 const char *version = PQparameterStatus(conn, "crdb_version"); 136 if (version == NULL) { 137 fprintf(stderr, "ERROR PQparameterStatus: crdb_version not reported: %s\n", PQgeterror()); 138 return 1; 139 } 140 if (strncmp(version, "CockroachDB ", strlen("CockroachDB ")) != 0) { 141 fprintf(stderr, "crdb_version mismatch: '%s' doesn't start with 'CockroachDB '\n", version); 142 return 1; 143 } 144 145 146 /* Always call first on any conn that is to be used with libpqtypes */ 147 PQinitTypes(conn); 148 149 PGparam *param = PQparamCreate(conn); 150 151 PGbool b = 1; 152 if (!PQputf(param, "%bool", b)) { 153 fprintf(stderr, "ERROR PQputf(bool): %s\n", PQgeterror()); 154 return 1; 155 } 156 157 char bytes[] = "hello"; 158 PGbytea bytea; 159 bytea.len = sizeof(bytes); 160 bytea.data = bytes; 161 if (!PQputf(param, "%bytea", &bytea)) { 162 fprintf(stderr, "ERROR PQputf(bytea): %s\n", PQgeterror()); 163 return 1; 164 } 165 166 // '1401-01-19' 167 PGdate date; 168 // TODO(jordan): put this back when #28099 is fixed. 169 // date.isbc = 1; 170 date.isbc = 0; 171 date.year = 1401; 172 date.mon = 0; 173 date.mday = 19; 174 if (!PQputf(param, "%date", &date)) { 175 fprintf(stderr, "ERROR PQputf(date): %s\n", PQgeterror()); 176 return 1; 177 } 178 179 PGnumeric numeric1 = "42"; 180 if (!PQputf(param, "%numeric", numeric1)) { 181 fprintf(stderr, "ERROR PQputf(numeric): %s\n", PQgeterror()); 182 return 1; 183 } 184 185 PGnumeric numeric2 = "-1728718718271827121233.1212121212"; 186 if (!PQputf(param, "%numeric", numeric2)) { 187 fprintf(stderr, "ERROR PQputf(numeric): %s\n", PQgeterror()); 188 return 1; 189 } 190 191 PGfloat8 f8 = 123456.789; 192 if (!PQputf(param, "%float8", f8)) { 193 fprintf(stderr, "ERROR PQputf(float8): %s\n", PQgeterror()); 194 return 1; 195 } 196 197 PGint8 i8 = INT_MAX; 198 if (!PQputf(param, "%int8", i8)) { 199 fprintf(stderr, "ERROR PQputf(int8): %s\n", PQgeterror()); 200 return 1; 201 } 202 203 // "20 years 8 months 9 hours 10 mins 15 secs 123456 usecs" 204 PGinterval interval; 205 interval.years = 20; 206 interval.mons = 8; 207 interval.days = 0; // not used, set to 0 208 interval.hours = 9; 209 interval.mins = 10; 210 interval.secs = 15; 211 interval.usecs = 123456; 212 // TODO(tamird,nvanbenschoten): implement interval binary encoding/decoding. 213 if (0) { 214 if (!PQputf(param, "%interval", &interval)) { 215 fprintf(stderr, "ERROR PQputf(interval): %s\n", PQgeterror()); 216 return 1; 217 } 218 } 219 220 PGtext text = "foobar"; 221 if (!PQputf(param, "%text", text)) { 222 fprintf(stderr, "ERROR PQputf(text): %s\n", PQgeterror()); 223 return 1; 224 } 225 226 // '2000-01-19 10:41:06' 227 PGtimestamp ts; 228 ts.epoch = 948278466; // expected, but not used in PQputf. 229 ts.date.isbc = 0; 230 ts.date.year = 2000; 231 ts.date.mon = 0; 232 ts.date.mday = 19; 233 ts.time.hour = 10; 234 ts.time.min = 41; 235 ts.time.sec = 6; 236 ts.time.usec = 0; 237 ts.time.withtz = 0; 238 ts.time.gmtoff = 0; // PQputf normalizes to GMT, so set and expect 0. 239 if (!PQputf(param, "%timestamp", &ts)) { 240 fprintf(stderr, "ERROR PQputf(timestamp): %s\n", PQgeterror()); 241 return 1; 242 } 243 244 // '2000-01-19 10:41:06-05' 245 PGtimestamp tstz; 246 tstz.epoch = 948278466; 247 tstz.date.isbc = 0; 248 tstz.date.year = 2000; 249 tstz.date.mon = 0; 250 tstz.date.mday = 19; 251 tstz.time.hour = 10; 252 tstz.time.min = 41; 253 tstz.time.sec = 6; 254 tstz.time.usec = 0; 255 tstz.time.withtz = 1; 256 tstz.time.gmtoff = 0; 257 258 if (!PQputf(param, "%timestamptz", &tstz)) { 259 fprintf(stderr, "ERROR PQputf(timestamptz): %s\n", PQgeterror()); 260 return 1; 261 } 262 263 char uuidBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 264 PGuuid uuid = uuidBytes; 265 if (!PQputf(param, "%uuid", uuid)) { 266 fprintf(stderr, "ERROR PQputf(uuid): %s\n", PQgeterror()); 267 return 1; 268 } 269 270 PGint8 i; 271 PGarray arr; 272 273 arr.ndims = 0; 274 arr.param = PQparamCreate(conn); 275 int arrLen = 100; 276 PGint8 expectedArr[arrLen]; 277 278 for (i = 0; i < arrLen; i++) { 279 expectedArr[i] = i; 280 if (!PQputf(arr.param, "%int8", i)) { 281 fprintf(stderr, "ERROR PQputf(arr elem): %s\n", PQgeterror()); 282 return 1; 283 } 284 } 285 if (!PQputf(param, "%int8[]", &arr)) { 286 fprintf(stderr, "ERROR PQputf(arr): %s\n", PQgeterror()); 287 return 1; 288 } 289 290 // resultFormat: 0 for text, 1 for binary. 291 for (int resultFormat = 0; resultFormat <= 1; ++resultFormat) { 292 PGresult *result = PQparamExec(conn, param, query, resultFormat); 293 if(!result) { 294 fprintf(stderr, "ERROR: %s\n", PQgeterror()); 295 return 1; 296 } 297 298 int i = 0; 299 300 PGbool recvb; 301 if (!PQgetf(result, 0, "%bool", i++, &recvb)) { 302 fprintf(stderr, "ERROR resultFormat=%d PQgetf(bool): %s\n", resultFormat, PQgeterror()); 303 return 1; 304 } 305 if (recvb != b) { 306 fprintf(stderr, "resultFormat=%d expected: %d, got: %d\n", resultFormat, b, recvb); 307 return 1; 308 } 309 310 PGbytea recvbytea; 311 if (!PQgetf(result, 0, "%bytea", i++, &recvbytea)) { 312 fprintf(stderr, "ERROR resultFormat=%d PQgetf(bytea): %s\n", resultFormat, PQgeterror()); 313 return 1; 314 } 315 if (memcmp(recvbytea.data, bytea.data, 316 MIN(recvbytea.len, bytea.len) // lint: uppercase function OK 317 ) != 0) { 318 fprintf(stderr, "resultFormat=%d expected (%d bytes): ", resultFormat, bytea.len); 319 for (int i = 0; i < bytea.len; ++i) { 320 fprintf(stderr, "%c", bytea.data[i]); 321 } 322 fprintf(stderr, " got (%d bytes): ", recvbytea.len); 323 for (int i = 0; i < recvbytea.len; ++i) { 324 fprintf(stderr, "%c", recvbytea.data[i]); 325 } 326 fprintf(stderr, "\n"); 327 return 1; 328 } 329 330 PGdate recvdate; 331 if (!PQgetf(result, 0, "%date", i++, &recvdate)) { 332 fprintf(stderr, "ERROR resultFormat=%d PQgetf(date): %s\n", resultFormat, PQgeterror()); 333 return 1; 334 } 335 if (!dateEqual(recvdate, date)) { 336 fprintf(stderr, "resultFormat=%d expected:\n", resultFormat); 337 datePrint(date); 338 fprintf(stderr, "\ngot:\n"); 339 datePrint(recvdate); 340 return 1; 341 } 342 343 PGnumeric recvnumeric1; 344 if (!PQgetf(result, 0, "%numeric", i++, &recvnumeric1)) { 345 fprintf(stderr, "ERROR resultFormat=%d PQgetf(numeric): %s\n", resultFormat, PQgeterror()); 346 return 1; 347 } 348 if (strcmp(recvnumeric1, numeric1)) { 349 fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, numeric1, recvnumeric1); 350 return 1; 351 } 352 353 PGnumeric recvnumeric2; 354 if (!PQgetf(result, 0, "%numeric", i++, &recvnumeric2)) { 355 fprintf(stderr, "ERROR resultFormat=%d PQgetf(numeric): %s\n", resultFormat, PQgeterror()); 356 return 1; 357 } 358 if (strcmp(recvnumeric2, numeric2)) { 359 fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, numeric2, recvnumeric2); 360 return 1; 361 } 362 363 PGfloat8 recvf8; 364 if (!PQgetf(result, 0, "%float8", i++, &recvf8)) { 365 fprintf(stderr, "ERROR resultFormat=%d PQgetf(float8): %s\n", resultFormat, PQgeterror()); 366 return 1; 367 } 368 if (recvf8 != f8) { 369 fprintf(stderr, "resultFormat=%d expected: %f, got: %f\n", resultFormat, f8, recvf8); 370 return 1; 371 } 372 373 PGint8 recvi8; 374 if (!PQgetf(result, 0, "%int8", i++, &recvi8)) { 375 fprintf(stderr, "ERROR resultFormat=%d PQgetf(int8): %s\n", resultFormat, PQgeterror()); 376 return 1; 377 } 378 if (recvi8 != i8) { 379 fprintf(stderr, "resultFormat=%d expected: %lld, got: %lld\n", resultFormat, i8, recvi8); 380 return 1; 381 } 382 383 // TODO(tamird,nvanbenschoten): implement interval binary encoding/decoding. 384 if (0) { 385 PGinterval recvinterval; 386 if (!PQgetf(result, 0, "%interval", i++, &recvinterval)) { 387 fprintf(stderr, "ERROR resultFormat=%d PQgetf(interval): %s\n", resultFormat, PQgeterror()); 388 return 1; 389 } 390 if (!intervalEqual(recvinterval, interval)) { 391 fprintf(stderr, "resultFormat=%d expected:\n", resultFormat); 392 intervalPrint(interval); 393 fprintf(stderr, "\ngot:\n"); 394 intervalPrint(recvinterval); 395 return 1; 396 } 397 } 398 399 PGtext recvtext; 400 if (!PQgetf(result, 0, "%text", i++, &recvtext)) { 401 fprintf(stderr, "ERROR resultFormat=%d PQgetf(text): %s\n", resultFormat, PQgeterror()); 402 return 1; 403 } 404 if (strcmp(recvtext, text)) { 405 fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, text, recvtext); 406 return 1; 407 } 408 409 PGtimestamp recvts; 410 if (!PQgetf(result, 0, "%timestamp", i++, &recvts)) { 411 fprintf(stderr, "ERROR resultFormat=%d PQgetf(timestamp): %s\n", resultFormat, PQgeterror()); 412 return 1; 413 } 414 if (!timestampEqual(recvts, ts)) { 415 fprintf(stderr, "resultFormat=%d expected:\n", resultFormat); 416 timestampPrint(ts); 417 fprintf(stderr, "\ngot:\n"); 418 timestampPrint(recvts); 419 return 1; 420 } 421 422 PGtimestamp recvtstz; 423 if (!PQgetf(result, 0, "%timestamptz", i++, &recvtstz)) { 424 fprintf(stderr, "ERROR resultFormat=%d PQgetf(timestamptz): %s\n", resultFormat, PQgeterror()); 425 return 1; 426 } 427 428 if (!timestampEqual(recvtstz, tstz)) { 429 fprintf(stderr, "resultFormat=%d expected:\n", resultFormat); 430 timestampPrint(tstz); 431 fprintf(stderr, "\ngot:\n"); 432 timestampPrint(recvtstz); 433 return 1; 434 } 435 436 PGuuid recvuuid; 437 if (!PQgetf(result, 0, "%uuid", i++, &recvuuid)) { 438 fprintf(stderr, "ERROR resultFormat=%d PQgetf(uuid): %s\n", resultFormat, PQgeterror()); 439 return 1; 440 } 441 if (strcmp(recvuuid, uuid)) { 442 fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, uuid, recvuuid); 443 return 1; 444 } 445 446 // Libpqtypes doesn't support text array decoding. 447 if (resultFormat == 1) { 448 PGarray recvarr; 449 if (!PQgetf(result, 0, "%int8[]", i++, &recvarr)) { 450 fprintf(stderr, "ERROR resultFormat=%d PQgetf(arr): %s\n", resultFormat, PQgeterror()); 451 return 1; 452 } 453 int n = PQntuples(recvarr.res); 454 if (arrLen != n) { 455 fprintf(stderr, "expected array of size %d, got %d\n", arrLen, n); 456 return 1; 457 } 458 int result[arrLen]; 459 PGint8 val; 460 for (int i = 0; i < arrLen; i++) { 461 PQgetf(recvarr.res, i, "%int8", 0, &val); 462 if (val != expectedArr[i]) { 463 fprintf(stderr, "resultFormat=%d expected %lld at pos %d; got %lld\n", resultFormat, expectedArr[i], i, val); 464 return 1; 465 } 466 } 467 } 468 } 469 470 return 0; 471 }