/* int8in() */ Datum int8in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); int64 result; (void) scanint8(str, false, &result); PG_RETURN_INT64(result); }
/* * 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; }
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); }
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; }
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; }