コード例 #1
0
ファイル: handler.c プロジェクト: KingDuckZ/dindexer
static int
checkTypeLookups(PGresult *res, PGregisterType *types, int count)
{
	int i;
	int ntups = PQntuples(res);

  /* The tuple count must match the requested count.  The server omits
   * tuples for types it did not find.  For those it did find, it returns
   * a sequenctial index.  The first gap found is our missing type.  This
   * only reports about the first missing type.
   */
  if (ntups == count)
		return TRUE;

 	for (i=0; i < ntups; i++)
	{
		int idx;

		if (!PQgetf(res, i, "%int4", 0, &idx))
			return FALSE;

		/* 'i' should always match idx-1, postgresql arrays are 1-based.
		 * This is a missing type, first gap in the sequence.
		 */
		if (i != idx-1)
			break;
	}

	PQseterror("server type lookup failed: could not find '%s'",
		types[i].typname);

	return FALSE;
}
コード例 #2
0
ファイル: handler.c プロジェクト: KingDuckZ/dindexer
int
PQregisterResult(PGconn *conn, int which, PGregisterType *types,
	int count, PGresult *res)
{
	int i;
	PGtypeData *connData;
	char typname[PQT_MAXIDLEN + 1];
	char typschema[PQT_MAXIDLEN + 1];
	/* inherit typput and typget from record type */
	PGtypeHandler *h_rec = pqt_gethandler(NULL, 0, "pg_catalog", "record");

	PQseterror(NULL);

	if (!conn)
	{
		PQseterror("PGconn cannot be NULL");
		return FALSE;
	}

	if (!res)
	{
		PQseterror("PGresult cannot be NULL");
		return FALSE;
	}

	if (which == PQT_SUBCLASS)
	{
		PQseterror("Cannot call PQregisterResult for a subclass registration.");
		return FALSE;
	}

	if (!(connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc)))
	{
		PQseterror("PGconn is missing event data");
		return FALSE;
	}

	if (!types)
	{
		PQseterror("PGregisterType[] cannot be NULL");
		return FALSE;
	}

	if (count < 0)
	{
		PQseterror("PGregisterType[] count cannot be less than zero");
		return FALSE;
	}

	if(!checkTypeLookups(res, types, count))
		return FALSE;

	for (i=0; i < PQntuples(res); i++)
	{
		int flags;
		PGint2 typlen;
		PGtypeHandler *h;

		if (which == PQT_USERDEFINED && !types[i].typput && !types[i].typget)
		{
			PQseterror("Must provide a put and/or a get routine: '%s'",
				types[i].typname);
			return FALSE;
		}

		/* make sure conn's type handlers array is large enough */
		if (!expandHandlers(connData))
			return FALSE;

		/* create the handler */
		h = &connData->typhandlers[connData->typhcnt];
		memset(h, 0, sizeof(PGtypeHandler));

		if (!PQgetf(res, i, "%oid %oid %int2", 1, &h->typoid,
			2, &h->typoid_array, 3, &typlen))
		{
			return FALSE;
		}

		h->id = connData->typhcnt + countof(pg_handlers);
		h->typlen = (int) typlen;
		h->base_id = -1;

		if (which == PQT_USERDEFINED)
		{
			h->typput = types[i].typput;
			h->typget = types[i].typget;
		}
		else
		{
			h->typput = h_rec->typput;
			h->typget = h_rec->typget;
		}

		/* parse out type and schema names again */
		(void ) pqt_parsetype(types[i].typname, typschema, typname, &flags, 1);
		pqt_strcpy(h->typschema, sizeof(h->typschema), typschema);
		pqt_strcpy(h->typname, sizeof(h->typname), typname);

		/* Process composite attributes */
		if(which == PQT_COMPOSITE)
		{
			PGtext attrs;
			int nattrs;
			PGrecordAttDesc *attDescs;

			if (!PQgetf(res, i, "%text", 4, &attrs))
			{
				return FALSE;
			}

			if (!(attDescs = initAttDescs(h, attrs)))
				return FALSE;

			for (nattrs=0; *attrs; nattrs++)
			{
				char *p;
				char *name;
				int len;

				/* Attribute Text Encoding:
				 *   "attoid,attlen,atttypmod,name_hex attoid,etc..."
				 */

				attDescs[nattrs].attoid    = (int) strtol(attrs, &attrs, 10);
				attDescs[nattrs].attlen    = (int) strtol(attrs + 1, &attrs, 10);
				attDescs[nattrs].atttypmod = (int) strtol(attrs + 1, &attrs, 10);

				/* skip comma before name */
				attrs++;

				/* attribute name in hex */
				if (!(p = strchr(attrs, ' ')))
					p = attrs + strlen(attrs); /* last attr, point at NUL */

				/* truncate name if it exceeds buffer */
				len = (int) (p - attrs);
				if (len >= (int) sizeof(attDescs[nattrs].attname))
					len = (int) (sizeof(attDescs[nattrs].attname) - 1);

				/* hex decode and copy */
				for (name = attDescs[nattrs].attname; attrs < p; attrs += 2)
					*name++ = (char) (pqt_hex_to_dec(attrs[0]) << 4)
						| pqt_hex_to_dec(attrs[1]);
				*name = 0;
			}

			h->nattrs = nattrs;
			h->attDescs = attDescs;
		}

		connData->typhcnt++;
	}

	return TRUE;
}
コード例 #3
0
ファイル: test.c プロジェクト: tamird/cockroach
int main(int argc, char *argv[]) {
	if (argc != 2) {
		fprintf(stderr, "usage: %s QUERY", argv[0]);
	}
	char *query = argv[1];

	PGconn *conn = PQconnectdb("");
	if (PQstatus(conn) != CONNECTION_OK) {
		fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
		return 1;
	}

	const char *version = PQparameterStatus(conn, "crdb_version");
	if (version == NULL) {
		fprintf(stderr, "ERROR PQparameterStatus: crdb_version not reported: %s\n", PQgeterror());
		return 1;
	}
	if (strncmp(version, "CockroachDB ", strlen("CockroachDB ")) != 0) {
		fprintf(stderr, "crdb_version mismatch: '%s' doesn't start with 'CockroachDB '\n", version);
		return 1;
	}

	/* Always call first on any conn that is to be used with libpqtypes */
	PQinitTypes(conn);

	PGparam *param = PQparamCreate(conn);

	PGbool b = 1;
	if (!PQputf(param, "%bool", b)) {
		fprintf(stderr, "ERROR PQputf(bool): %s\n", PQgeterror());
		return 1;
	}

	char bytes[] = "hello";
	PGbytea bytea;
	bytea.len = sizeof(bytes);
	bytea.data = bytes;
	if (!PQputf(param, "%bytea", &bytea)) {
		fprintf(stderr, "ERROR PQputf(bytea): %s\n", PQgeterror());
		return 1;
	}

	// '1401-01-19 BC'
	PGdate date;
	date.isbc = 1;
	date.year = 1401;
	date.mon  = 0;
	date.mday = 19;
	if (!PQputf(param, "%date", &date)) {
		fprintf(stderr, "ERROR PQputf(date): %s\n", PQgeterror());
		return 1;
	}

	PGnumeric numeric1 = "42";
	if (!PQputf(param, "%numeric", numeric1)) {
		fprintf(stderr, "ERROR PQputf(numeric): %s\n", PQgeterror());
		return 1;
	}

	PGnumeric numeric2 = "-1728718718271827121233.1212121212";
	if (!PQputf(param, "%numeric", numeric2)) {
		fprintf(stderr, "ERROR PQputf(numeric): %s\n", PQgeterror());
		return 1;
	}

	PGfloat8 f8 = 123456.789;
	if (!PQputf(param, "%float8", f8)) {
		fprintf(stderr, "ERROR PQputf(float8): %s\n", PQgeterror());
		return 1;
	}

	PGint8 i8 = INT_MAX;
	if (!PQputf(param, "%int8", i8)) {
		fprintf(stderr, "ERROR PQputf(int8): %s\n", PQgeterror());
		return 1;
	}

	// "20 years 8 months 9 hours 10 mins 15 secs 123456 usecs"
	PGinterval interval;
	interval.years = 20;
	interval.mons  = 8;
	interval.days  = 0; // not used, set to 0
	interval.hours = 9;
	interval.mins  = 10;
	interval.secs  = 15;
	interval.usecs = 123456;
	// TODO(tamird,nvanbenschoten): implement interval binary encoding/decoding.
	if (0) {
		if (!PQputf(param, "%interval", &interval)) {
			fprintf(stderr, "ERROR PQputf(interval): %s\n", PQgeterror());
			return 1;
		}
	}

	PGtext text = "foobar";
	if (!PQputf(param, "%text", text)) {
		fprintf(stderr, "ERROR PQputf(text): %s\n", PQgeterror());
		return 1;
	}

	// '2000-01-19 10:41:06'
	PGtimestamp ts;
	ts.epoch       = 948278466; // expected, but not used in PQputf.
	ts.date.isbc   = 0;
	ts.date.year   = 2000;
	ts.date.mon    = 0;
	ts.date.mday   = 19;
	ts.time.hour   = 10;
	ts.time.min    = 41;
	ts.time.sec    = 6;
	ts.time.usec   = 0;
	ts.time.withtz = 0;
	ts.time.gmtoff = 0; // PQputf normalizes to GMT, so set and expect 0.
	if (!PQputf(param, "%timestamp", &ts)) {
		fprintf(stderr, "ERROR PQputf(timestamp): %s\n", PQgeterror());
		return 1;
	}

	// '2000-01-19 10:41:06-05'
	PGtimestamp tstz;
	tstz.epoch       = 948278466;
	tstz.date.isbc   = 0;
	tstz.date.year   = 2000;
	tstz.date.mon    = 0;
	tstz.date.mday   = 19;
	tstz.time.hour   = 10;
	tstz.time.min    = 41;
	tstz.time.sec    = 6;
	tstz.time.usec   = 0;
	tstz.time.withtz = 1;
	tstz.time.gmtoff = 0;
	if (!PQputf(param, "%timestamptz", &tstz)) {
		fprintf(stderr, "ERROR PQputf(timestamptz): %s\n", PQgeterror());
		return 1;
	}

	char uuidBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
	PGuuid uuid = uuidBytes;
	if (!PQputf(param, "%uuid", uuid)) {
		fprintf(stderr, "ERROR PQputf(uuid): %s\n", PQgeterror());
		return 1;
	}

	PGint8 i;
	PGarray arr;

	arr.ndims = 0;
	arr.param = PQparamCreate(conn);
	int arrLen = 100;
	PGint8 expectedArr[arrLen];

	for (i = 0; i < arrLen; i++) {
		expectedArr[i] = i;
		if (!PQputf(arr.param, "%int8", i)) {
			fprintf(stderr, "ERROR PQputf(arr elem): %s\n", PQgeterror());
			return 1;
		}
	}
	if (!PQputf(param, "%int8[]", &arr)) {
		fprintf(stderr, "ERROR PQputf(arr): %s\n", PQgeterror());
		return 1;
	}

	// resultFormat: 0 for text, 1 for binary.
	for (int resultFormat = 0; resultFormat <= 1; ++resultFormat) {
			PGresult *result = PQparamExec(conn, param, query, resultFormat);
			if(!result) {
				fprintf(stderr, "ERROR: %s\n", PQgeterror());
				return 1;
			}

			int i = 0;

			PGbool recvb;
			if (!PQgetf(result, 0, "%bool", i++, &recvb)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(bool): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (recvb != b) {
				fprintf(stderr, "resultFormat=%d expected: %d, got: %d\n", resultFormat, b, recvb);
				return 1;
			}

			PGbytea recvbytea;
			if (!PQgetf(result, 0, "%bytea", i++, &recvbytea)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(bytea): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (memcmp(recvbytea.data, bytea.data,
				   MIN(recvbytea.len, bytea.len) // lint: uppercase function OK
				) != 0) {
				fprintf(stderr, "resultFormat=%d expected (%d bytes): ", resultFormat, bytea.len);
				for (int i = 0; i < bytea.len; ++i) {
					fprintf(stderr, "%c", bytea.data[i]);
				}
				fprintf(stderr, " got (%d bytes): ", recvbytea.len);
				for (int i = 0; i < recvbytea.len; ++i) {
					fprintf(stderr, "%c", recvbytea.data[i]);
				}
				fprintf(stderr, "\n");
				return 1;
			}

			PGdate recvdate;
			if (!PQgetf(result, 0, "%date", i++, &recvdate)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(date): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (!dateEqual(recvdate, date)) {
				fprintf(stderr, "resultFormat=%d expected:\n", resultFormat);
				datePrint(date);
				fprintf(stderr, "\ngot:\n");
				datePrint(recvdate);
				return 1;
			}

			PGnumeric recvnumeric1;
			if (!PQgetf(result, 0, "%numeric", i++, &recvnumeric1)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(numeric): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (strcmp(recvnumeric1, numeric1)) {
				fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, numeric1, recvnumeric1);
				return 1;
			}

			PGnumeric recvnumeric2;
			if (!PQgetf(result, 0, "%numeric", i++, &recvnumeric2)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(numeric): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (strcmp(recvnumeric2, numeric2)) {
				fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, numeric2, recvnumeric2);
				return 1;
			}

			PGfloat8 recvf8;
			if (!PQgetf(result, 0, "%float8", i++, &recvf8)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(float8): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (recvf8 != f8) {
				fprintf(stderr, "resultFormat=%d expected: %f, got: %f\n", resultFormat, f8, recvf8);
				return 1;
			}

			PGint8 recvi8;
			if (!PQgetf(result, 0, "%int8", i++, &recvi8)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(int8): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (recvi8 != i8) {
				fprintf(stderr, "resultFormat=%d expected: %lld, got: %lld\n", resultFormat, i8, recvi8);
				return 1;
			}

			// TODO(tamird,nvanbenschoten): implement interval binary encoding/decoding.
			if (0) {
				PGinterval recvinterval;
				if (!PQgetf(result, 0, "%interval", i++, &recvinterval)) {
					fprintf(stderr, "ERROR resultFormat=%d PQgetf(interval): %s\n", resultFormat, PQgeterror());
					return 1;
				}
				if (!intervalEqual(recvinterval, interval)) {
					fprintf(stderr, "resultFormat=%d expected:\n", resultFormat);
					intervalPrint(interval);
					fprintf(stderr, "\ngot:\n");
					intervalPrint(recvinterval);
					return 1;
				}
			}

			PGtext recvtext;
			if (!PQgetf(result, 0, "%text", i++, &recvtext)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(text): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (strcmp(recvtext, text)) {
				fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, text, recvtext);
				return 1;
			}

			PGtimestamp recvts;
			if (!PQgetf(result, 0, "%timestamp", i++, &recvts)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(timestamp): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (!timestampEqual(recvts, ts)) {
				fprintf(stderr, "resultFormat=%d expected:\n", resultFormat);
				timestampPrint(ts);
				fprintf(stderr, "\ngot:\n");
				timestampPrint(recvts);
				return 1;
			}

			PGtimestamp recvtstz;
			if (!PQgetf(result, 0, "%timestamptz", i++, &recvtstz)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(timestamptz): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (!timestampEqual(recvtstz, tstz)) {
				fprintf(stderr, "resultFormat=%d expected:\n", resultFormat);
				timestampPrint(tstz);
				fprintf(stderr, "\ngot:\n");
				timestampPrint(recvtstz);
				return 1;
			}

			PGuuid recvuuid;
			if (!PQgetf(result, 0, "%uuid", i++, &recvuuid)) {
				fprintf(stderr, "ERROR resultFormat=%d PQgetf(uuid): %s\n", resultFormat, PQgeterror());
				return 1;
			}
			if (strcmp(recvuuid, uuid)) {
				fprintf(stderr, "resultFormat=%d expected: %s, got: %s\n", resultFormat, uuid, recvuuid);
				return 1;
			}

			// Libpqtypes doesn't support text array decoding.
			if (resultFormat == 1) {
				PGarray recvarr;
				if (!PQgetf(result, 0, "%int8[]", i++, &recvarr)) {
					fprintf(stderr, "ERROR resultFormat=%d PQgetf(arr): %s\n", resultFormat, PQgeterror());
					return 1;
				}
				int n = PQntuples(recvarr.res);
				if (arrLen != n) {
					fprintf(stderr, "expected array of size %d, got %d\n", arrLen, n);
					return 1;
				}
				int result[arrLen];
				PGint8 val;
				for (int i = 0; i < arrLen; i++) {
					PQgetf(recvarr.res, i, "%int8", 0, &val);
					if (val != expectedArr[i]) {
						fprintf(stderr, "resultFormat=%d expected %lld at pos %d; got %lld\n", resultFormat, expectedArr[i], i, val);
						return 1;
					}
				}
			}
	}

	return 0;
}