<commit_before>/*----------------------------------------------------------------------
 *
 * pgquarrel -- comparing database schemas
 *
 * sequence.c
 *     Generate SEQUENCE commands
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * CREATE SEQUENCE
 * DROP SEQUENCE
 * ALTER SEQUENCE
 * ALTER SEQUENCE ... OWNED BY (table.c)
 * COMMENT ON SEQUENCE
 *
 * TODO
 *
 * ALTER SEQUENCE ... OWNED BY (create sequence)
 * ALTER SEQUENCE ... RENAME TO
 * ALTER SEQUENCE ... SET SCHEMA
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Copyright (c) 2015-2017, <NAME>
 *
 * ---------------------------------------------------------------------
 */
#include "sequence.h"


PQLSequence *
getSequences(PGconn *c, int *n)
{
	PQLSequence		*s;
	PGresult		*res;
	int				i;

	logNoise("sequence: server version: %d", PQserverVersion(c));

	if (PQserverVersion(c) >= 90100)	/* extension support */
	{
		res = PQexec(c,
				 "SELECT c.oid, n.nspname, c.relname, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) WHERE relkind = 'S' AND nspname !~ '^pg_' AND nspname <> 'information_schema' AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE c.oid = d.objid AND d.deptype = 'e') ORDER BY nspname, relname");
	}
	else
	{
		res = PQexec(c,
				 "SELECT c.oid, n.nspname, c.relname, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) WHERE relkind = 'S' AND nspname !~ '^pg_' AND nspname <> 'information_schema' ORDER BY nspname, relname");
	}

	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		logError("query failed: %s", PQresultErrorMessage(res));
		PQclear(res);
		PQfinish(c);
		/* XXX leak another connection? */
		exit(EXIT_FAILURE);
	}

	*n = PQntuples(res);
	if (*n > 0)
		s = (PQLSequence *) malloc(*n * sizeof(PQLSequence));
	else
		s = NULL;

	logDebug("number of sequences in server: %d", *n);

	for (i = 0; i < *n; i++)
	{
		s[i].obj.oid = strtoul(PQgetvalue(res, i, PQfnumber(res, "oid")), NULL, 10);
		s[i].obj.schemaname = strdup(PQgetvalue(res, i, PQfnumber(res, "nspname")));
		s[i].obj.objectname = strdup(PQgetvalue(res, i, PQfnumber(res, "relname")));
		if (PQgetisnull(res, i, PQfnumber(res, "description")))
			s[i].comment = NULL;
		else
			s[i].comment = strdup(PQgetvalue(res, i, PQfnumber(res, "description")));

		s[i].owner = strdup(PQgetvalue(res, i, PQfnumber(res, "relowner")));
		if (PQgetisnull(res, i, PQfnumber(res, "relacl")))
			s[i].acl = NULL;
		else
			s[i].acl = strdup(PQgetvalue(res, i, PQfnumber(res, "relacl")));

		/*
		 * These values are not assigned here (see getSequenceAttributes), but
		 * default values are essential to avoid having trouble in
		 * freeSequences.
		 */
		s[i].startvalue = NULL;
		s[i].incvalue = NULL;
		s[i].minvalue = NULL;
		s[i].maxvalue = NULL;
		s[i].cache = NULL;

		/*
		 * Security labels are not assigned here (see
		 * getSequenceSecurityLabels), but default values are essential to
		 * avoid having trouble in freeSequences.
		 */
		s[i].nseclabels = 0;
		s[i].seclabels = NULL;

		logDebug("sequence \"%s\".\"%s\"", s[i].obj.schemaname, s[i].obj.objectname);
	}

	PQclear(res);

	return s;
}

void
getSequenceAttributes(PGconn *c, PQLSequence *s)
{
	char		*schema = formatObjectIdentifier(s->obj.schemaname);
	char		*seqname = formatObjectIdentifier(s->obj.objectname);
	char		*query = NULL;
	int			nquery = 0;
	PGresult	*res;

	/* determine how many characters will be written by snprintf */
	nquery = snprintf(query, nquery,
				 "SELECT increment_by, start_value, max_value, min_value, cache_value, is_cycled FROM %s.%s",
				 schema, seqname);

	nquery++;
	query = (char *) malloc(nquery * sizeof(char));	/* make enough room for query */
	snprintf(query, nquery,
				 "SELECT increment_by, start_value, max_value, min_value, cache_value, is_cycled FROM %s.%s",
				 schema, seqname);

	logNoise("sequence: query size: %d ; query: %s", nquery, query);

	res = PQexec(c, query);

	free(query);
	free(schema);
	free(seqname);

	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		logError("query failed: %s", PQresultErrorMessage(res));
		PQclear(res);
		PQfinish(c);
		/* XXX leak another connection? */
		exit(EXIT_FAILURE);
	}

	if (PQntuples(res) != 1)
		logError("query to get sequence information returns %d row(s) (expected 1)",
				 PQntuples(res));
	else
	{
		s->incvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "increment_by")));
		s->startvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "start_value")));
		s->maxvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "max_value")));
		s->minvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "min_value")));
		s->cache = strdup(PQgetvalue(res, 0, PQfnumber(res, "cache_value")));
		s->cycle = (PQgetvalue(res, 0, PQfnumber(res, "is_cycled"))[0] == 't');
	}

	PQclear(res);
}

void
getSequenceSecurityLabels(PGconn *c, PQLSequence *s)
{
	char		query[200];
	PGresult	*res;
	int			i;

	if (PQserverVersion(c) < 90100)
	{
		logWarning("ignoring security labels because server does not support it");
		return;
	}
<commit_msg>Sequence has a new catalog<commit_after>/*----------------------------------------------------------------------
 *
 * pgquarrel -- comparing database schemas
 *
 * sequence.c
 *     Generate SEQUENCE commands
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * CREATE SEQUENCE
 * DROP SEQUENCE
 * ALTER SEQUENCE
 * ALTER SEQUENCE ... OWNED BY (table.c)
 * COMMENT ON SEQUENCE
 *
 * TODO
 *
 * ALTER SEQUENCE ... OWNED BY (create sequence)
 * ALTER SEQUENCE ... RENAME TO
 * ALTER SEQUENCE ... SET SCHEMA
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * Copyright (c) 2015-2017, <NAME>
 *
 * ---------------------------------------------------------------------
 */
#include "sequence.h"


PQLSequence *
getSequences(PGconn *c, int *n)
{
	PQLSequence		*s;
	PGresult		*res;
	int				i;

	logNoise("sequence: server version: %d", PQserverVersion(c));

	if (PQserverVersion(c) >= 90100)	/* extension support */
	{
		res = PQexec(c,
				 "SELECT c.oid, n.nspname, c.relname, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) WHERE relkind = 'S' AND nspname !~ '^pg_' AND nspname <> 'information_schema' AND NOT EXISTS(SELECT 1 FROM pg_depend d WHERE c.oid = d.objid AND d.deptype = 'e') ORDER BY nspname, relname");
	}
	else
	{
		res = PQexec(c,
				 "SELECT c.oid, n.nspname, c.relname, obj_description(c.oid, 'pg_class') AS description, pg_get_userbyid(c.relowner) AS relowner, relacl FROM pg_class c INNER JOIN pg_namespace n ON (c.relnamespace = n.oid) WHERE relkind = 'S' AND nspname !~ '^pg_' AND nspname <> 'information_schema' ORDER BY nspname, relname");
	}

	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		logError("query failed: %s", PQresultErrorMessage(res));
		PQclear(res);
		PQfinish(c);
		/* XXX leak another connection? */
		exit(EXIT_FAILURE);
	}

	*n = PQntuples(res);
	if (*n > 0)
		s = (PQLSequence *) malloc(*n * sizeof(PQLSequence));
	else
		s = NULL;

	logDebug("number of sequences in server: %d", *n);

	for (i = 0; i < *n; i++)
	{
		s[i].obj.oid = strtoul(PQgetvalue(res, i, PQfnumber(res, "oid")), NULL, 10);
		s[i].obj.schemaname = strdup(PQgetvalue(res, i, PQfnumber(res, "nspname")));
		s[i].obj.objectname = strdup(PQgetvalue(res, i, PQfnumber(res, "relname")));
		if (PQgetisnull(res, i, PQfnumber(res, "description")))
			s[i].comment = NULL;
		else
			s[i].comment = strdup(PQgetvalue(res, i, PQfnumber(res, "description")));

		s[i].owner = strdup(PQgetvalue(res, i, PQfnumber(res, "relowner")));
		if (PQgetisnull(res, i, PQfnumber(res, "relacl")))
			s[i].acl = NULL;
		else
			s[i].acl = strdup(PQgetvalue(res, i, PQfnumber(res, "relacl")));

		/*
		 * These values are not assigned here (see getSequenceAttributes), but
		 * default values are essential to avoid having trouble in
		 * freeSequences.
		 */
		s[i].startvalue = NULL;
		s[i].incvalue = NULL;
		s[i].minvalue = NULL;
		s[i].maxvalue = NULL;
		s[i].cache = NULL;

		/*
		 * Security labels are not assigned here (see
		 * getSequenceSecurityLabels), but default values are essential to
		 * avoid having trouble in freeSequences.
		 */
		s[i].nseclabels = 0;
		s[i].seclabels = NULL;

		logDebug("sequence \"%s\".\"%s\"", s[i].obj.schemaname, s[i].obj.objectname);
	}

	PQclear(res);

	return s;
}

void
getSequenceAttributes(PGconn *c, PQLSequence *s)
{
	char		*query = NULL;
	int			nquery = 0;
	PGresult	*res;

	/* pg_sequence catalog is new in 10 */
	if (PQserverVersion(c) >= 100000)
	{
		/* determine how many characters will be written by snprintf */
		nquery = snprintf(query, nquery,
					 "SELECT seqincrement, seqstart, seqmax, seqmin, seqcache, seqcycle FROM pg_sequence WHERE seqrelid = %u",
					 s->obj.oid);

		nquery++;
		query = (char *) malloc(nquery * sizeof(char));	/* make enough room for query */
		snprintf(query, nquery,
					 "SELECT seqincrement, seqstart, seqmax, seqmin, seqcache, seqcycle FROM pg_sequence WHERE seqrelid = %u",
					 s->obj.oid);
	}
	else
	{
		char *schema = formatObjectIdentifier(s->obj.schemaname);
		char *seqname = formatObjectIdentifier(s->obj.objectname);

		/* determine how many characters will be written by snprintf */
		nquery = snprintf(query, nquery,
					 "SELECT increment_by AS seqincrement, start_value AS seqstart, max_value AS seqmax, min_value AS seqmin, cache_value AS seqcache, is_cycled AS seqcycle FROM %s.%s",
					 schema, seqname);

		nquery++;
		query = (char *) malloc(nquery * sizeof(char));	/* make enough room for query */
		snprintf(query, nquery,
					 "SELECT increment_by AS seqincrement, start_value AS seqstart, max_value AS seqmax, min_value AS seqmin, cache_value AS seqcache, is_cycled AS seqcycle FROM %s.%s",
					 schema, seqname);
		free(schema);
		free(seqname);
	}

	logNoise("sequence: query size: %d ; query: %s", nquery, query);

	res = PQexec(c, query);

	free(query);

	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		logError("query failed: %s", PQresultErrorMessage(res));
		PQclear(res);
		PQfinish(c);
		/* XXX leak another connection? */
		exit(EXIT_FAILURE);
	}

	if (PQntuples(res) != 1)
		logError("query to get sequence information returns %d row(s) (expected 1)",
				 PQntuples(res));
	else
	{
		s->incvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "seqincrement")));
		s->startvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "seqstart")));
		s->maxvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "seqmax")));
		s->minvalue = strdup(PQgetvalue(res, 0, PQfnumber(res, "seqmin")));
		s->cache = strdup(PQgetvalue(res, 0, PQfnumber(res, "seqcache")));
		s->cycle = (PQgetvalue(res, 0, PQfnumber(res, "seqcycle"))[0] == 't');
	}

	PQclear(res);
}

void
getSequenceSecurityLabels(PGconn *c, PQLSequence *s)
{
	char		query[200];
	PGresult	*res;
	int			i;

	if (PQserverVersion(c) < 90100)
	{
		logWarning("ignoring security labels because server does not support it");
		return;
	}

{'fraction_non_alphanumeric': 0.18787115350008998, 'fraction_numerical': 0.007378081698758323, 'mean_word_length': 3.717741935483871, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '602425', 'n_tokens_mistral': 4462, 'n_tokens_neox': 4035, 'n_words': 1014}