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  }