Improved performance of sparsevec_in

This commit is contained in:
Andrew Kane
2024-04-13 15:42:16 -07:00
parent 20fb2e0797
commit 545ae30057
2 changed files with 106 additions and 115 deletions

View File

@@ -174,19 +174,16 @@ sparsevec_in(PG_FUNCTION_ARGS)
char *lit = PG_GETARG_CSTRING(0); char *lit = PG_GETARG_CSTRING(0);
int32 typmod = PG_GETARG_INT32(2); int32 typmod = PG_GETARG_INT32(2);
int dim; int dim;
char *pt; char *pt = lit;
char *stringEnd; char *stringEnd;
SparseVector *result; SparseVector *result;
float *rvalues; float *rvalues;
char *litcopy = pstrdup(lit);
char *str = litcopy;
int32 *indices; int32 *indices;
float *values; float *values;
int maxNnz; int maxNnz;
int nnz = 0; int nnz = 0;
maxNnz = 1; maxNnz = 1;
pt = str;
while (*pt != '\0') while (*pt != '\0')
{ {
if (*pt == ',') if (*pt == ',')
@@ -203,137 +200,135 @@ sparsevec_in(PG_FUNCTION_ARGS)
indices = palloc(maxNnz * sizeof(int32)); indices = palloc(maxNnz * sizeof(int32));
values = palloc(maxNnz * sizeof(float)); values = palloc(maxNnz * sizeof(float));
while (sparsevec_isspace(*str)) pt = lit;
str++;
if (*str != '{') while (sparsevec_isspace(*pt))
pt++;
if (*pt != '{')
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit), errmsg("invalid input syntax for type sparsevec: \"%s\"", lit),
errdetail("Vector contents must start with \"{\"."))); errdetail("Vector contents must start with \"{\".")));
str++; pt++;
while (sparsevec_isspace(*str)) while (sparsevec_isspace(*pt))
str++; pt++;
pt = strtok(str, ","); if (*pt == '}')
stringEnd = pt; pt++;
else
while (pt != NULL && *stringEnd != '}')
{ {
long index; for (;;)
float value; {
long index;
float value;
/* TODO Better error */ /* TODO Better error */
if (nnz == maxNnz) if (nnz == maxNnz)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("ran out of buffer: \"%s\"", lit))); errmsg("ran out of buffer: \"%s\"", lit)));
while (sparsevec_isspace(*pt))
pt++;
/* Check for empty string like float4in */
if (*pt == '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
/* Use similar logic as int2vectorin */
errno = 0;
index = strtol(pt, &stringEnd, 10);
if (stringEnd == pt)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
if (errno == ERANGE || index < 1 || index > INT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("index \"%ld\" is out of range for type sparsevec", index)));
pt = stringEnd;
while (sparsevec_isspace(*pt))
pt++;
if (*pt != ':')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
while (sparsevec_isspace(*pt))
pt++; pt++;
/* Check for empty string like float4in */ while (sparsevec_isspace(*pt))
if (*pt == '\0') pt++;
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
/* Use similar logic as int2vectorin */ errno = 0;
errno = 0;
index = strtol(pt, &stringEnd, 10);
if (stringEnd == pt) /* Use strtof like float4in to avoid a double-rounding problem */
ereport(ERROR, /* Postgres sets LC_NUMERIC to C on startup */
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), value = strtof(pt, &stringEnd);
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
if (errno == ERANGE || index < 1 || index > INT_MAX) if (stringEnd == pt)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("index \"%ld\" is out of range for type sparsevec", index))); errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
if (stringEnd == pt) /* Check for range error like float4in */
ereport(ERROR, if (errno == ERANGE && (value == 0 || isinf(value)))
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), ereport(ERROR,
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit))); (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type sparsevec", pt)));
while (sparsevec_isspace(*stringEnd)) /* Do not store zero values */
stringEnd++; if (value != 0)
{
indices[nnz] = index;
values[nnz] = value;
nnz++;
}
if (*stringEnd != ':') pt = stringEnd;
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
stringEnd++; while (sparsevec_isspace(*pt))
pt++;
while (sparsevec_isspace(*stringEnd)) if (*pt == ',')
stringEnd++; pt++;
else if (*pt == '}')
pt = stringEnd; {
errno = 0; pt++;
break;
/* Use strtof like float4in to avoid a double-rounding problem */ }
/* Postgres sets LC_NUMERIC to C on startup */ else
value = strtof(pt, &stringEnd); ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
if (stringEnd == pt) errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
/* Check for range error like float4in */
if (errno == ERANGE && (value == 0 || isinf(value)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type sparsevec", pt)));
/* TODO Decide whether to store zero values */
if (value != 0)
{
indices[nnz] = index;
values[nnz] = value;
nnz++;
} }
while (sparsevec_isspace(*stringEnd))
stringEnd++;
if (*stringEnd != '\0' && *stringEnd != '}')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
pt = strtok(NULL, ",");
} }
if (stringEnd == NULL || *stringEnd != '}') while (sparsevec_isspace(*pt))
pt++;
if (*pt != '/')
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit), errmsg("invalid input syntax for type sparsevec: \"%s\"", lit),
errdetail("Unexpected end of input."))); errdetail("Unexpected end of input.")));
stringEnd++; pt++;
while (sparsevec_isspace(*stringEnd)) while (sparsevec_isspace(*pt))
stringEnd++; pt++;
if (*stringEnd != '/')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit),
errdetail("Unexpected end of input.")));
stringEnd++;
while (sparsevec_isspace(*stringEnd))
stringEnd++;
/* Use similar logic as int2vectorin */ /* Use similar logic as int2vectorin */
errno = 0; errno = 0;
pt = stringEnd;
dim = strtol(pt, &stringEnd, 10); dim = strtol(pt, &stringEnd, 10);
if (stringEnd == pt) if (stringEnd == pt)
@@ -341,18 +336,18 @@ sparsevec_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit))); errmsg("invalid input syntax for type sparsevec: \"%s\"", lit)));
/* Only whitespace is allowed after the closing brace */ pt = stringEnd;
while (sparsevec_isspace(*stringEnd))
stringEnd++;
if (*stringEnd != '\0') /* Only whitespace is allowed after the closing brace */
while (sparsevec_isspace(*pt))
pt++;
if (*pt != '\0')
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type sparsevec: \"%s\"", lit), errmsg("invalid input syntax for type sparsevec: \"%s\"", lit),
errdetail("Junk after closing."))); errdetail("Junk after closing.")));
pfree(litcopy);
CheckDim(dim); CheckDim(dim);
CheckExpectedDim(typmod, dim); CheckExpectedDim(typmod, dim);

View File

@@ -25,12 +25,10 @@ SELECT '{'::sparsevec;
ERROR: invalid input syntax for type sparsevec: "{" ERROR: invalid input syntax for type sparsevec: "{"
LINE 1: SELECT '{'::sparsevec; LINE 1: SELECT '{'::sparsevec;
^ ^
DETAIL: Unexpected end of input.
SELECT '{ '::sparsevec; SELECT '{ '::sparsevec;
ERROR: invalid input syntax for type sparsevec: "{ " ERROR: invalid input syntax for type sparsevec: "{ "
LINE 1: SELECT '{ '::sparsevec; LINE 1: SELECT '{ '::sparsevec;
^ ^
DETAIL: Unexpected end of input.
SELECT '{}'::sparsevec; SELECT '{}'::sparsevec;
ERROR: invalid input syntax for type sparsevec: "{}" ERROR: invalid input syntax for type sparsevec: "{}"
LINE 1: SELECT '{}'::sparsevec; LINE 1: SELECT '{}'::sparsevec;
@@ -47,11 +45,9 @@ LINE 1: SELECT '{}/1a'::sparsevec;
DETAIL: Junk after closing. DETAIL: Junk after closing.
-- TODO fix -- TODO fix
SELECT '{,}/1'::sparsevec; SELECT '{,}/1'::sparsevec;
sparsevec ERROR: invalid input syntax for type sparsevec: "{,}/1"
----------- LINE 1: SELECT '{,}/1'::sparsevec;
{}/1 ^
(1 row)
SELECT '{1,}/1'::sparsevec; SELECT '{1,}/1'::sparsevec;
ERROR: invalid input syntax for type sparsevec: "{1,}/1" ERROR: invalid input syntax for type sparsevec: "{1,}/1"
LINE 1: SELECT '{1,}/1'::sparsevec; LINE 1: SELECT '{1,}/1'::sparsevec;