Esempio n. 1
0
/* int8in()
 */
Datum
int8in(PG_FUNCTION_ARGS)
{
    char	   *str = PG_GETARG_CSTRING(0);
    int64		result;

    (void) scanint8(str, false, &result);
    PG_RETURN_INT64(result);
}
Esempio n. 2
0
/*
 * Get the max size of the relation across segments
 */
int64
cdbRelMaxSegSize(Relation rel)
{
	int64 size = 0;
	int i;
	CdbPgResults cdb_pgresults = {NULL, 0};
	StringInfoData buffer;

	char *schemaName;
	char *relName;

	/*
	 * Let's ask the QEs for the size of the relation
	 */
	initStringInfo(&buffer);

	schemaName = get_namespace_name(RelationGetNamespace(rel));
	if (schemaName == NULL)
		elog(ERROR, "cache lookup failed for namespace %d",
			 RelationGetNamespace(rel));
	relName = RelationGetRelationName(rel);

	/*
	 * Safer to pass names than oids, just in case they get out of sync between QD and QE,
	 * which might happen with a toast table or index, I think (but maybe not)
	 */
	appendStringInfo(&buffer, "select pg_relation_size('%s.%s')",
					 quote_identifier(schemaName), quote_identifier(relName));

	CdbDispatchCommand(buffer.data, DF_WITH_SNAPSHOT, &cdb_pgresults);

	for (i = 0; i < cdb_pgresults.numResults; i++)
	{
		struct pg_result * pgresult = cdb_pgresults.pg_results[i];
		if (PQresultStatus(pgresult) != PGRES_TUPLES_OK)
		{
			cdbdisp_clearCdbPgResults(&cdb_pgresults);
			elog(ERROR,"cdbRelMaxSegSize: resultStatus not tuples_Ok: %s %s",
				 PQresStatus(PQresultStatus(pgresult)),PQresultErrorMessage(pgresult));
		}
		else
		{
			Assert(PQntuples(pgresult) == 1);
			int64 tempsize = 0;
			(void) scanint8(PQgetvalue(pgresult, 0, 0), false, &tempsize);
			if (tempsize > size)
				size = tempsize;
		}
	}

	pfree(buffer.data);

	cdbdisp_clearCdbPgResults(&cdb_pgresults);

	return size;
}
Esempio n. 3
0
static void
parse_output_parameters(List *options, uint32 *protocol_version,
						List **publication_names)
{
	ListCell   *lc;
	bool		protocol_version_given = false;
	bool		publication_names_given = false;

	foreach(lc, options)
	{
		DefElem    *defel = (DefElem *) lfirst(lc);

		Assert(defel->arg == NULL || IsA(defel->arg, String));

		/* Check each param, whether or not we recognize it */
		if (strcmp(defel->defname, "proto_version") == 0)
		{
			int64		parsed;

			if (protocol_version_given)
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
			protocol_version_given = true;

			if (!scanint8(strVal(defel->arg), true, &parsed))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("invalid proto_version")));

			if (parsed > PG_UINT32_MAX || parsed < 0)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("proto_version \"%s\" out of range",
								strVal(defel->arg))));

			*protocol_version = (uint32) parsed;
		}
		else if (strcmp(defel->defname, "publication_names") == 0)
		{
			if (publication_names_given)
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("conflicting or redundant options")));
			publication_names_given = true;

			if (!SplitIdentifierString(strVal(defel->arg), ',',
									   publication_names))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_NAME),
						 errmsg("invalid publication_names syntax")));
		}
		else
			elog(ERROR, "unrecognized pgoutput option: %s", defel->defname);
	}
Esempio n. 4
0
static bool
GetNextArgument(const char *ptr, char **arg, Oid *argtype, const char **endptr, const char *path, bool argistype)
{
    const char *p;
    bool		first_arg = false;
    int			len;

    p = ptr;
    while (isspace((unsigned char) *p))
        p++;

    if (*p == '(')
        first_arg = true;
    else if (*p == ',')
        first_arg = false;
    else if (*p == ')')
    {
        p++;
        while (isspace((unsigned char) *p))
            p++;

        if (*p != '\0')
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", path)));

        *endptr = p;
        return false;
    }
    else
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("function call syntax error: %s", path)));

    p++;
    while (isspace((unsigned char) *p))
        p++;

    if (first_arg && *p == ')')
    {
        p++;
        while (isspace((unsigned char) *p))
            p++;

        if (*p != '\0')
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", path)));

        *endptr = p;
        return false;
    }

    *argtype = UNKNOWNOID;
    if (argistype)
    {
        /* argument is data type name */
        const char *startptr;
        bool		inparenthesis;
        int			nparentheses;
        char	   *str;
        int32		typmod;

        startptr = p;
        inparenthesis = false;
        nparentheses = 0;
        while (*p != '\0' && (inparenthesis || (*p != ',' && *p != ')')))
        {
            if (*p == '(')
            {
                if (inparenthesis)
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("function call syntax error: %s", path)));

                inparenthesis = true;
                nparentheses++;
                if (nparentheses > 1)
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("function call syntax error: %s", path)));
            }

            if (*p == ')')
                inparenthesis = false;

            p++;
        }

        if (p == startptr)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", path)));

        while (isspace((unsigned char) *(p - 1)))
            p--;

        len = p - startptr;
        str = palloc(len + 1);
        memcpy(str, startptr, len);
        str[len] = '\0';
        *arg = str;

        /* Use full parser to resolve the type name */
        parseTypeString(*arg, argtype, &typmod);
    }
    else if (*p == '\'')
    {
        /* argument is string constants */
        StringInfoData	buf;

        initStringInfo(&buf);

        p++;
        while (*p != '\0')
        {
            if (*p == '\'')
            {
                if (*(p + 1) == '\'')
                    p++;
                else
                    break;
            }

            appendStringInfoCharMacro(&buf, *p++);
        }

        if (*p != '\'')
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", path)));

        p++;
        *arg = buf.data;
    }
    else if (pg_strncasecmp(p, "NULL", strlen("NULL")) == 0)
    {
        /* argument is NULL */
        p += strlen("NULL");
        *arg = NULL;
    }
    else
    {
        /* argument is numeric constants */
        bool		minus;
        const char *startptr;
        char	   *str;
        int64		val64;

        /* parse plus operator and minus operator */
        minus = false;
        while (*p == '+' || *p == '-')
        {
            if (*p == '-')
            {
                /* this is standard SQL comment */
                if (*(p + 1) == '-')
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("function call syntax error: %s", path)));
                minus = !minus;
            }

            p++;
            while (isspace((unsigned char) *p))
                p++;
        }

        startptr = p;
        while (!isspace((unsigned char) *p) && *p != ',' && *p != ')' &&
                *p != '\0')
            p++;

        len = p - startptr;
        if (len == 0)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("function call syntax error: %s", path)));

        str = palloc(len + 2);
        snprintf(str, len + 2, "%c%s", minus ? '-' : '+', startptr);

        /* could be an oversize integer as well as a float ... */
        if (scanint8(str, true, &val64))
        {
            /*
             * It might actually fit in int32. Probably only INT_MIN can
             * occur, but we'll code the test generally just to be sure.
             */
            int32		val32 = (int32) val64;

            if (val64 == (int64) val32)
                *argtype = INT4OID;
            else
                *argtype = INT8OID;
        }
        else
        {
            /* arrange to report location if numeric_in() fails */
            DirectFunctionCall3(numeric_in, CStringGetDatum(str + 1),
                                ObjectIdGetDatum(InvalidOid),
                                Int32GetDatum(-1));

            *argtype = NUMERICOID;
        }

        /* Check for numeric constants. */
        *arg = str;
    }

    *endptr = p;
    return true;
}
Esempio n. 5
0
int64 cdbRelSize(Relation rel)
{
	int64	size = 0;
	int		i;
	int 	resultCount = 0;
	struct pg_result **results = NULL;
	StringInfoData errbuf;
	StringInfoData buffer;

	char	*schemaName;
	char	*relName;	

	if (last_cache_entry  >= 0)
	{
		for (i=0; i < relsize_cache_size; i++)
		{
			if (relsize_cache[i].relOid == RelationGetRelid(rel))
				return relsize_cache[i].size;
		}
	}

	/*
	 * Let's ask the QEs for the size of the relation
	 */
	initStringInfo(&buffer);
	initStringInfo(&errbuf);

	schemaName = get_namespace_name(RelationGetNamespace(rel));
	if (schemaName == NULL)
		elog(ERROR, "cache lookup failed for namespace %d",
			 RelationGetNamespace(rel));
	relName = RelationGetRelationName(rel);

	/* 
	 * Safer to pass names than oids, just in case they get out of sync between QD and QE,
	 * which might happen with a toast table or index, I think (but maybe not)
	 */
	appendStringInfo(&buffer, "select pg_relation_size('%s.%s')",
					 quote_identifier(schemaName), quote_identifier(relName));

	/* 
	 * In the future, it would be better to send the command to only one QE for the optimizer's needs,
	 * but for ALTER TABLE, we need to be sure if the table has any rows at all.
	 */
	results = cdbdisp_dispatchRMCommand(buffer.data, true, &errbuf, &resultCount);

	if (errbuf.len > 0)
	{
		ereport(WARNING, (errmsg("cdbRelSize error (gathered %d results from cmd '%s')", resultCount, buffer.data),
						  errdetail("%s", errbuf.data)));
		pfree(errbuf.data);
		pfree(buffer.data);
		
		return -1;
	}
	else
	{
										
		for (i = 0; i < resultCount; i++)
		{
			if (PQresultStatus(results[i]) != PGRES_TUPLES_OK)
			{
				elog(ERROR,"cdbRelSize: resultStatus not tuples_Ok: %s   %s",PQresStatus(PQresultStatus(results[i])),PQresultErrorMessage(results[i]));
			}
			else
			{
				/*
				 * Due to funkyness in the current dispatch agent code, instead of 1 result 
				 * per QE with 1 row each, we can get back 1 result per dispatch agent, with
				 * one row per QE controlled by that agent.
				 */
				int j;
				for (j = 0; j < PQntuples(results[i]); j++)
				{
					int64 tempsize = 0;
					(void) scanint8(PQgetvalue(results[i], j, 0), false, &tempsize);
					if (tempsize > size)
					 	size = tempsize;
				}
			}
		}
	
		pfree(errbuf.data);
		pfree(buffer.data);

		for (i = 0; i < resultCount; i++)
			PQclear(results[i]);
	
		free(results);
	}

	if (size >= 0)	/* Cache the size even if it is zero, as table might be empty */
	{
		if (last_cache_entry < 0)
			last_cache_entry = 0;

		relsize_cache[last_cache_entry].relOid = RelationGetRelid(rel);
		relsize_cache[last_cache_entry].size = size;
		last_cache_entry = (last_cache_entry+1) % relsize_cache_size;
	}

	return size;
}