Esempio n. 1
0
/*
 * the result is also available with the global variable 'connection'.
 */
void
reconnect(int elevel)
{
	StringInfoData	buf;
	char		   *new_password;

	disconnect();
	initStringInfo(&buf);
	if (dbname && dbname[0])
		appendStringInfo(&buf, "dbname=%s ", dbname);
	if (host && host[0])
		appendStringInfo(&buf, "host=%s ", host);
	if (port && port[0])
		appendStringInfo(&buf, "port=%s ", port);
	if (username && username[0])
		appendStringInfo(&buf, "user=%s ", username);
	if (password && password[0])
		appendStringInfo(&buf, "password=%s ", password);

	connection = pgut_connect(buf.data, prompt_password, elevel);

	/* update password */
	if (connection)
	{
		new_password = PQpass(connection);
		if (new_password && new_password[0] &&
			(password == NULL || strcmp(new_password, password) != 0))
		{
			free(password);
			password = pgut_strdup(new_password);
		}
	}

	termStringInfo(&buf);
}
Esempio n. 2
0
int
main(int argc, char *argv[])
{
	PGconn			*conn;
	StringInfoData	 conn_info;
	int				 num_options;

	num_options = pgut_getopt(argc, argv, options);

	/* command-line arguments is not necessary */
	if (num_options != argc)
		ereport(ERROR,
			(errcode(EINVAL),
			 errmsg("too many argumetns")));

	/* can't specified the mode two or more */
	if ((mode_list && (mode_size || mode_report || mode_snapshot || mode_delete)) ||
		(mode_size && (mode_report || mode_snapshot || mode_delete)) ||
		(mode_report && (mode_snapshot || mode_delete)) ||
		(mode_snapshot && mode_delete))
		ereport(ERROR,
			(errcode(EINVAL),
			 errmsg("can't specify two or more mode")));

	/* connect to database */
	initStringInfo(&conn_info);
	if (dbname && dbname[0])
		appendStringInfo(&conn_info, "dbname=%s ", dbname);
	if (host && host[0])
		appendStringInfo(&conn_info, "host=%s ", host);
	if (port && port[0])
		appendStringInfo(&conn_info, "port=%s ", port);
	if (username && username[0])
		appendStringInfo(&conn_info, "user=%s ", username);

	conn = pgut_connect(conn_info.data, prompt_password, ERROR);
	termStringInfo(&conn_info);

	/* execute a specified operation */
	if (mode_list)
		do_list(conn, instid);
	else if (mode_size)
		do_size(conn);
	else if (mode_report)
		do_report(conn, mode_report,
			instid, beginid, endid, begindate, enddate, output);
	else if (mode_snapshot)
		do_snapshot(conn, mode_snapshot);
	else if (mode_delete)
		do_delete(conn, mode_delete);
	else
		ereport(ERROR,
			(errcode(EINVAL),
			 errmsg("please specify operation option (-l, -s, -r, -S, -D)")));

	pgut_disconnect(conn);
	return 0;
}
Esempio n. 3
0
void
execute_with_format_args(int expected, const char *format, int nargs, Oid argtypes[], Datum values[], const bool nulls[], ...)
{
	va_list			ap;
	StringInfoData	sql;

	initStringInfo(&sql);
	va_start(ap, nulls);
	appendStringInfoVA_s(&sql, format, ap);
	va_end(ap);

	execute_with_args(expected, sql.data, nargs, argtypes, values, nulls);

	termStringInfo(&sql);
}
Esempio n. 4
0
/* execute sql with format */
void
execute_with_format(int expected, const char *format, ...)
{
	va_list			ap;
	StringInfoData	sql;
	int				ret;

	initStringInfo(&sql);
	va_start(ap, format);
	appendStringInfoVA_s(&sql, format, ap);
	va_end(ap);

	if (sql.len == 0)
		elog(WARNING, "execute_with_format(%s)", format);
	ret = SPI_exec(sql.data, 0);
	if EXEC_FAILED(ret, expected)
		elog(ERROR, "query failed: (sql=%s, code=%d, expected=%d)", sql.data, ret, expected);

	termStringInfo(&sql);
}
Esempio n. 5
0
/*
 * Re-organize one table.
 */
static void
reorg_one_table(const reorg_table *table, const char *orderby)
{
	PGresult	   *res;
	const char	   *params[1];
	int				num;
	int				i;
	int				num_waiting = 0;
	char		   *vxid;
	char			buffer[12];
	StringInfoData	sql;

	initStringInfo(&sql);

	elog(DEBUG2, "---- reorg_one_table ----");
	elog(DEBUG2, "target_name    : %s", table->target_name);
	elog(DEBUG2, "target_oid     : %u", table->target_oid);
	elog(DEBUG2, "target_toast   : %u", table->target_toast);
	elog(DEBUG2, "target_tidx    : %u", table->target_tidx);
	elog(DEBUG2, "pkid           : %u", table->pkid);
	elog(DEBUG2, "ckid           : %u", table->ckid);
	elog(DEBUG2, "create_pktype  : %s", table->create_pktype);
	elog(DEBUG2, "create_log     : %s", table->create_log);
	elog(DEBUG2, "create_trigger : %s", table->create_trigger);
	elog(DEBUG2, "alter_table    : %s", table->alter_table);
	elog(DEBUG2, "create_table   : %s", table->create_table);
	elog(DEBUG2, "drop_columns   : %s", table->drop_columns ? table->drop_columns : "(skipped)");
	elog(DEBUG2, "delete_log     : %s", table->delete_log);
	elog(DEBUG2, "lock_table     : %s", table->lock_table);
	elog(DEBUG2, "sql_peek       : %s", table->sql_peek);
	elog(DEBUG2, "sql_insert     : %s", table->sql_insert);
	elog(DEBUG2, "sql_delete     : %s", table->sql_delete);
	elog(DEBUG2, "sql_update     : %s", table->sql_update);
	elog(DEBUG2, "sql_pop        : %s", table->sql_pop);

	/*
	 * 1. Setup workspaces and a trigger.
	 */
	elog(DEBUG2, "---- setup ----");
	lock_exclusive(utoa(table->target_oid, buffer), table->lock_table);

	/*
	 * Check z_reorg_trigger is the trigger executed at last so that
	 * other before triggers cannot modify triggered tuples.
	 */
	params[0] = utoa(table->target_oid, buffer);

	res = execute("SELECT reorg.conflicted_triggers($1)", 1, params);
	if (PQntuples(res) > 0)
		ereport(ERROR,
			(errcode(E_PG_COMMAND),
			 errmsg("trigger %s conflicted for %s",
					PQgetvalue(res, 0, 0), table->target_name)));
	PQclear(res);

	command(table->create_pktype, 0, NULL);
	command(table->create_log, 0, NULL);
	command(table->create_trigger, 0, NULL);
	command(table->alter_table, 0, NULL);
	printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.log_%u')", table->target_oid);
	command(sql.data, 0, NULL);
	command("COMMIT", 0, NULL);

	/*
	 * Register the table to be dropped on error. We use pktype as
	 * an advisory lock. The registration should be done after
	 * the first command succeeds.
	 */
	pgut_atexit_push(&reorg_cleanup, (void *) table);

	/*
	 * 2. Copy tuples into temp table.
	 */
	elog(DEBUG2, "---- copy tuples ----");

	command("BEGIN ISOLATION LEVEL SERIALIZABLE", 0, NULL);
	/* SET work_mem = maintenance_work_mem */
	command("SELECT set_config('work_mem', current_setting('maintenance_work_mem'), true)", 0, NULL);
	if (orderby && !orderby[0])
		command("SET LOCAL synchronize_seqscans = off", 0, NULL);
	res = execute(SQL_XID_SNAPSHOT, 0, NULL);
	vxid = strdup(PQgetvalue(res, 0, 0));
	PQclear(res);
	command(table->delete_log, 0, NULL);
	command(table->create_table, 0, NULL);
	printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.table_%u')", table->target_oid);
	if (table->drop_columns)
		command(table->drop_columns, 0, NULL);
	command(sql.data, 0, NULL);
	command("COMMIT", 0, NULL);

	/*
	 * 3. Create indexes on temp table.
	 */
	elog(DEBUG2, "---- create indexes ----");

	params[0] = utoa(table->target_oid, buffer);
	res = execute("SELECT indexrelid,"
		" reorg.reorg_indexdef(indexrelid, indrelid),"
		" indisvalid,"
		" pg_get_indexdef(indexrelid)"
		" FROM pg_index WHERE indrelid = $1", 1, params);

	num = PQntuples(res);
	for (i = 0; i < num; i++)
	{
		reorg_index	index;
		int			c = 0;
		const char *isvalid;
		const char *indexdef;

		index.target_oid = getoid(res, i, c++);
		index.create_index = getstr(res, i, c++);
		isvalid = getstr(res, i, c++);
		indexdef = getstr(res, i, c++);

		if (isvalid && isvalid[0] == 'f') {
			elog(WARNING, "skipping invalid index: %s", indexdef);
			continue;
		}

		elog(DEBUG2, "[%d]", i);
		elog(DEBUG2, "target_oid   : %u", index.target_oid);
		elog(DEBUG2, "create_index : %s", index.create_index);

		/*
		 * NOTE: If we want to create multiple indexes in parallel,
		 * we need to call create_index in multiple connections.
		 */
		command(index.create_index, 0, NULL);
	}
	PQclear(res);

	/*
	 * 4. Apply log to temp table until no tuples are left in the log
	 * and all of the old transactions are finished.
	 */
	for (;;)
	{
		num = apply_log(table, APPLY_COUNT);
		if (num > 0)
			continue;	/* there might be still some tuples, repeat. */

		/* old transactions still alive ? */
		params[0] = vxid;
		res = execute(SQL_XID_ALIVE, 1, params);
		num = PQntuples(res);

		if (num > 0)
		{
			/* Wait for old transactions.
			 * Only display the message below when the number of
			 * transactions we are waiting on changes (presumably,
			 * num_waiting should only go down), so as not to
			 * be too noisy.
			 */
			if (num != num_waiting)
			{
				elog(NOTICE, "Waiting for %d transactions to finish. First PID: %s", num, PQgetvalue(res, 0, 0));
				num_waiting = num;
			}

			PQclear(res);
			sleep(1);
			continue;
		}
		else
		{
			/* All old transactions are finished;
			 * go to next step. */
			PQclear(res);
			break;
		}
	}

	/*
	 * 5. Swap.
	 */
	elog(DEBUG2, "---- swap ----");
	lock_exclusive(utoa(table->target_oid, buffer), table->lock_table);
	apply_log(table, 0);
	params[0] = utoa(table->target_oid, buffer);
	command("SELECT reorg.reorg_swap($1)", 1, params);
	command("COMMIT", 0, NULL);

	/*
	 * 6. Drop.
	 */
	elog(DEBUG2, "---- drop ----");

	command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
	params[0] = utoa(table->target_oid, buffer);
	command("SELECT reorg.reorg_drop($1)", 1, params);
	command("COMMIT", 0, NULL);

	pgut_atexit_pop(&reorg_cleanup, (void *) table);
	free(vxid);

	/*
	 * 7. Analyze.
	 * Note that cleanup hook has been already uninstalled here because analyze
	 * is not an important operation; No clean up even if failed.
	 */
	if (analyze)
	{
		elog(DEBUG2, "---- analyze ----");

		command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
		printfStringInfo(&sql, "ANALYZE %s", table->target_name);
		command(sql.data, 0, NULL);
		command("COMMIT", 0, NULL);
	}

	termStringInfo(&sql);
}
Esempio n. 6
0
/*
 * Call reorg_one_table for the target table or each table in a database.
 */
static bool
reorg_one_database(const char *orderby, const char *table)
{
	bool			ret = true;
	PGresult	   *res;
	int				i;
	int				num;
	StringInfoData	sql;

	initStringInfo(&sql);

	reconnect(ERROR);

	/* Disable statement timeout. */
	command("SET statement_timeout = 0", 0, NULL);

	/* Restrict search_path to system catalog. */
	command("SET search_path = pg_catalog, pg_temp, public", 0, NULL);

	/* To avoid annoying "create implicit ..." messages. */
	command("SET client_min_messages = warning", 0, NULL);

	/* acquire target tables */
	appendStringInfoString(&sql, "SELECT * FROM reorg.tables WHERE ");
	if (table)
	{
		appendStringInfoString(&sql, "relid = $1::regclass");
		res = execute_elevel(sql.data, 1, &table, DEBUG2);
	}
	else
	{
		appendStringInfoString(&sql, "pkid IS NOT NULL");
		if (!orderby)
			appendStringInfoString(&sql, " AND ckid IS NOT NULL");
		res = execute_elevel(sql.data, 0, NULL, DEBUG2);
	}

	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		if (sqlstate_equals(res, SQLSTATE_INVALID_SCHEMA_NAME))
		{
			/* Schema reorg does not exist. Skip the database. */
			ret = false;
			goto cleanup;
		}
		else
		{
			/* exit otherwise */
			printf("%s", PQerrorMessage(connection));
			PQclear(res);
			exit(1);
		}
	}

	num = PQntuples(res);

	for (i = 0; i < num; i++)
	{
		reorg_table	table;
		const char *create_table;
		const char *ckey;
		int			c = 0;

		table.target_name = getstr(res, i, c++);
		table.target_oid = getoid(res, i, c++);
		table.target_toast = getoid(res, i, c++);
		table.target_tidx = getoid(res, i, c++);
		table.pkid = getoid(res, i, c++);
		table.ckid = getoid(res, i, c++);

		if (table.pkid == 0)
			ereport(ERROR,
				(errcode(E_PG_COMMAND),
				 errmsg("relation \"%s\" must have a primary key or not-null unique keys", table.target_name)));

		table.create_pktype = getstr(res, i, c++);
		table.create_log = getstr(res, i, c++);
		table.create_trigger = getstr(res, i, c++);
		table.alter_table = getstr(res, i, c++);

		create_table = getstr(res, i, c++);
		table.drop_columns = getstr(res, i, c++);
		table.delete_log = getstr(res, i, c++);
		table.lock_table = getstr(res, i, c++);
		ckey = getstr(res, i, c++);

		resetStringInfo(&sql);
		if (!orderby)
		{
			/* CLUSTER mode */
			if (ckey == NULL)
				ereport(ERROR,
					(errcode(E_PG_COMMAND),
					 errmsg("relation \"%s\" has no cluster key", table.target_name)));
			appendStringInfo(&sql, "%s ORDER BY %s", create_table, ckey);
            table.create_table = sql.data;
		}
		else if (!orderby[0])
		{
			/* VACUUM FULL mode */
            table.create_table = create_table;
		}
		else
		{
			/* User specified ORDER BY */
			appendStringInfo(&sql, "%s ORDER BY %s", create_table, orderby);
            table.create_table = sql.data;
		}

		table.sql_peek = getstr(res, i, c++);
		table.sql_insert = getstr(res, i, c++);
		table.sql_delete = getstr(res, i, c++);
		table.sql_update = getstr(res, i, c++);
		table.sql_pop = getstr(res, i, c++);

		reorg_one_table(&table, orderby);
	}

cleanup:
	PQclear(res);
	disconnect();
	termStringInfo(&sql);
	return ret;
}
Esempio n. 7
0
/**
 * @brief Performs data loading.
 *
 * Invokes pg_bulkload() user-defined function with given parameters
 * in single transaction.
 *
 * @return exitcode (always 0).
 */
static int
LoaderLoadMain(List *options)
{
	PGresult	   *res;
	const char	   *params[1];
	StringInfoData	buf;
	int				encoding;
	int				errors;
	ListCell	   *cell;

	if (options == NIL)
		ereport(ERROR,
			(errcode(EXIT_FAILURE),
			 errmsg("requires control file or command line options")));

	initStringInfo(&buf);
	reconnect(ERROR);
	encoding = PQclientEncoding(connection);

	elog(NOTICE, "BULK LOAD START");

	/* form options as text[] */
	appendStringInfoString(&buf, "{\"");
	foreach (cell, options)
	{
		const char *item = lfirst(cell);

		if (buf.len > 2)
			appendStringInfoString(&buf, "\",\"");

		/* escape " and \ */
		while (*item)
		{
			if (*item == '"' || *item == '\\')
			{
				appendStringInfoChar(&buf, '\\');
				appendStringInfoChar(&buf, *item);
				item++;
			}
			else if (!IS_HIGHBIT_SET(*item))
			{
				appendStringInfoChar(&buf, *item);
				item++;
			}
			else
			{
				int	n = PQmblen(item, encoding);
				appendBinaryStringInfo(&buf, item, n);
				item += n;
			}
		}
	}
	appendStringInfoString(&buf, "\"}");

	command("BEGIN", 0, NULL);
	params[0] = buf.data;
	res = execute("SELECT * FROM pg_bulkload($1)", 1, params);
	if (PQresultStatus(res) == PGRES_COPY_IN)
	{
		PQclear(res);
		res = RemoteLoad(connection, stdin, type_binary);
		if (PQresultStatus(res) != PGRES_TUPLES_OK)
			elog(ERROR, "copy failed: %s", PQerrorMessage(connection));
	}
	command("COMMIT", 0, NULL);

	errors = atoi(PQgetvalue(res, 0, 2)) +	/* parse errors */
			 atoi(PQgetvalue(res, 0, 3));	/* duplicate errors */

	elog(NOTICE, "BULK LOAD END\n"
				 "\t%s Rows skipped.\n"
				 "\t%s Rows successfully loaded.\n"
				 "\t%s Rows not loaded due to parse errors.\n"
				 "\t%s Rows not loaded due to duplicate errors.\n"
				 "\t%s Rows replaced with new rows.",
				 PQgetvalue(res, 0, 0), PQgetvalue(res, 0, 1),
				 PQgetvalue(res, 0, 2), PQgetvalue(res, 0, 3),
				 PQgetvalue(res, 0, 4));
	PQclear(res);

	disconnect();
	termStringInfo(&buf);

	if (errors > 0)
	{
		elog(WARNING, "some rows were not loaded due to errors.");
		return E_PG_USER;
	}
	else
		return 0;	/* succeeded without errors */
}
Esempio n. 8
0
PGconn *
pgut_connect(const char *info, YesNo prompt, int elevel)
{
	char	   *passwd;
	StringInfoData add_pass;

	if (prompt == YES)
	{
		passwd = prompt_for_password();
		initStringInfo(&add_pass);
		appendStringInfoString(&add_pass, info);
		appendStringInfo(&add_pass, " password=%s ", passwd);
	}
	else
	{
		passwd = NULL;
		add_pass.data = NULL;
	}

	/* Start the connection. Loop until we have a password if requested by backend. */
	for (;;)
	{
		PGconn	   *conn;
		CHECK_FOR_INTERRUPTS();

		if (!passwd)
			conn = PQconnectdb(info);
		else
			conn = PQconnectdb(add_pass.data);

		if (PQstatus(conn) == CONNECTION_OK)
		{
			pgutConn *c;

			c = pgut_new(pgutConn);
			c->conn = conn;
			c->cancel = NULL;

			pgut_conn_lock();
			c->next = pgut_connections;
			pgut_connections = c;
			pgut_conn_unlock();

			if (add_pass.data != NULL)
				termStringInfo(&add_pass);
			free(passwd);

			return conn;
		}

		if (conn && PQconnectionNeedsPassword(conn) && prompt != NO)
		{
			PQfinish(conn);
			free(passwd);
			passwd = prompt_for_password();
			if (add_pass.data != NULL)
	 			resetStringInfo(&add_pass);
			else
	 			initStringInfo(&add_pass);
			appendStringInfoString(&add_pass, info);
			appendStringInfo(&add_pass, " password=%s ", passwd);
			continue;
		}

		if (add_pass.data != NULL)
			termStringInfo(&add_pass);
		free(passwd);

		ereport(elevel,
			(errcode(E_PG_CONNECT),
			 errmsg("could not connect to database with \"%s\": %s",
				info, PQerrorMessage(conn))));
		PQfinish(conn);
		return NULL;
	}
}