Add defenses against invalid operator names passed in CREATE OPERATOR

arguments (where the parser doesn't check them already).  Minor code
cleanups too.
This commit is contained in:
Tom Lane 2001-10-22 19:34:13 +00:00
parent 970a2d1c91
commit a19f2605ed
1 changed files with 106 additions and 73 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.62 2001/10/22 19:34:13 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
@ -41,11 +41,6 @@ static Oid OperatorGet(char *operatorName,
char *rightTypeName,
bool *defined);
static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
char *operatorName,
Oid leftObjectId,
Oid rightObjectId);
static Oid OperatorShellMake(char *operatorName,
char *leftTypeName,
char *rightTypeName);
@ -66,6 +61,65 @@ static void OperatorDef(char *operatorName,
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
/*
* Check whether a proposed operator name is legal
*
* This had better match the behavior of parser/scan.l!
*
* We need this because the parser is not smart enough to check that
* the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
* are operator names rather than some other lexical entity.
*/
static bool
validOperatorName(const char *name)
{
size_t len = strlen(name);
/* Can't be empty or too long */
if (len == 0 || len >= NAMEDATALEN)
return false;
/* Can't contain any invalid characters */
/* Test string here should match op_chars in scan.l */
if (strspn(name, "~!@#^&|`?$+-*/%<>=") != len)
return false;
/* Can't contain slash-star or dash-dash (comment starts) */
if (strstr(name, "/*") || strstr(name, "--"))
return false;
/*
* For SQL92 compatibility, '+' and '-' cannot be the
* last char of a multi-char operator unless the operator
* contains chars that are not in SQL92 operators.
* The idea is to lex '=-' as two operators, but not
* to forbid operator names like '?-' that could not be
* sequences of SQL92 operators.
*/
if (len > 1 &&
(name[len-1] == '+' ||
name[len-1] == '-'))
{
int ic;
for (ic = len-2; ic >= 0; ic--)
{
if (strchr("~!@#^&|`?$%", name[ic]))
break;
}
if (ic < 0)
return false; /* nope, not valid */
}
/* != isn't valid either, because parser will convert it to <> */
if (strcmp(name, "!=") == 0)
return false;
return true;
}
/* ----------------------------------------------------------------
* OperatorGetWithOpenRelation
*
@ -157,7 +211,6 @@ OperatorGet(char *operatorName,
bool *defined)
{
Relation pg_operator_desc;
Oid operatorObjectId;
Oid leftObjectId = InvalidOid;
Oid rightObjectId = InvalidOid;
@ -215,24 +268,55 @@ OperatorGet(char *operatorName,
}
/* ----------------------------------------------------------------
* OperatorShellMakeWithOpenRelation
* OperatorShellMake
*
* Specify operator name and left and right type names,
* fill an operator struct with this info and NULL's,
* call heap_insert and return the Oid to the caller.
* ----------------------------------------------------------------
*/
static Oid
OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
char *operatorName,
Oid leftObjectId,
Oid rightObjectId)
OperatorShellMake(char *operatorName,
char *leftTypeName,
char *rightTypeName)
{
Relation pg_operator_desc;
Oid operatorObjectId;
Oid leftObjectId = InvalidOid;
Oid rightObjectId = InvalidOid;
bool leftDefined = false;
bool rightDefined = false;
int i;
HeapTuple tup;
Datum values[Natts_pg_operator];
char nulls[Natts_pg_operator];
Oid operatorObjectId;
NameData oname;
TupleDesc tupDesc;
/*
* validate operator name
*/
if (!validOperatorName(operatorName))
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
/*
* get the left and right type oid's for this operator
*/
if (leftTypeName)
leftObjectId = TypeGet(leftTypeName, &leftDefined);
if (rightTypeName)
rightObjectId = TypeGet(rightTypeName, &rightDefined);
if (!((OidIsValid(leftObjectId) && leftDefined) ||
(OidIsValid(rightObjectId) && rightDefined)))
elog(ERROR, "OperatorShellMake: the operand types are not valid");
/*
* open pg_operator
*/
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/*
* initialize our *nulls and *values arrays
*/
@ -243,7 +327,7 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
}
/*
* initialize *values with the operator name and input data types.
* initialize values[] with the operator name and input data types.
* Note that oprcode is set to InvalidOid, indicating it's a shell.
*/
i = 0;
@ -270,12 +354,10 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
*/
tupDesc = pg_operator_desc->rd_att;
tup = heap_formtuple(tupDesc,
values,
nulls);
tup = heap_formtuple(tupDesc, values, nulls);
/*
* insert our "shell" operator tuple and close the relation
* insert our "shell" operator tuple
*/
heap_insert(pg_operator_desc, tup);
operatorObjectId = tup->t_data->t_oid;
@ -289,63 +371,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
CatalogCloseIndices(Num_pg_operator_indices, idescs);
}
/*
* free the tuple and return the operator oid
*/
heap_freetuple(tup);
return operatorObjectId;
}
/* ----------------------------------------------------------------
* OperatorShellMake
*
* Specify operator name and left and right type names,
* fill an operator struct with this info and NULL's,
* call heap_insert and return the Oid
* to the caller.
* ----------------------------------------------------------------
*/
static Oid
OperatorShellMake(char *operatorName,
char *leftTypeName,
char *rightTypeName)
{
Relation pg_operator_desc;
Oid operatorObjectId;
Oid leftObjectId = InvalidOid;
Oid rightObjectId = InvalidOid;
bool leftDefined = false;
bool rightDefined = false;
/*
* get the left and right type oid's for this operator
*/
if (leftTypeName)
leftObjectId = TypeGet(leftTypeName, &leftDefined);
if (rightTypeName)
rightObjectId = TypeGet(rightTypeName, &rightDefined);
if (!((OidIsValid(leftObjectId) && leftDefined) ||
(OidIsValid(rightObjectId) && rightDefined)))
elog(ERROR, "OperatorShellMake: the operand types are not valid");
/*
* open pg_operator
*/
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/*
* add a "shell" operator tuple to the operator relation and recover
* the shell tuple's oid.
*/
operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
operatorName,
leftObjectId,
rightObjectId);
/*
* close the operator relation and return the oid.
*/
@ -484,6 +511,12 @@ OperatorDef(char *operatorName,
* filling in a previously-created shell.
*/
/*
* validate operator name
*/
if (!validOperatorName(operatorName))
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
/*
* look up the operator data types.
*