1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Make WITHOUT TIME ZONE the default for TIMESTAMP and TIME data types.

This is a big change from past behavior, but the last release was
 designed to handle this correctly for dump/restore upgrades.
Fix up handling of SET value arguments. Allow lists for most options at
 least at the parser level; multiple values may be rejected at the
 command processor of course.
Allow more variations on values for SET commands, including integer and
 float values where formerly stringy fields were required.
Check precision specification for date/time fields against the true
 precision range allowed by the data types. Especially useful with the
 new int8-based storage for these types, where precision is fixed and
 predictable.
Stub out a basic CREATE ASSERTION per SQL9x. Does not do anything (yet) but
 should be augmented as appropriate.
Minor fixups in braces and tabbing.
This commit is contained in:
Thomas G. Lockhart
2002-04-21 19:21:49 +00:00
parent e53f94ad68
commit 37cfb04094
2 changed files with 232 additions and 209 deletions

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.306 2002/04/21 00:26:43 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.307 2002/04/21 19:21:49 thomas Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -60,6 +60,7 @@
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "utils/numeric.h" #include "utils/numeric.h"
#include "utils/datetime.h" #include "utils/datetime.h"
#include "utils/date.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
@ -84,7 +85,9 @@ static int pfunc_num_args;
static Node *makeTypeCast(Node *arg, TypeName *typename); static Node *makeTypeCast(Node *arg, TypeName *typename);
static Node *makeStringConst(char *str, TypeName *typename); static Node *makeStringConst(char *str, TypeName *typename);
static Node *makeIntConst(int val);
static Node *makeFloatConst(char *str); static Node *makeFloatConst(char *str);
static Node *makeAConst(Value *v);
static Node *makeRowExpr(List *opr, List *largs, List *rargs); static Node *makeRowExpr(List *opr, List *largs, List *rargs);
static SelectStmt *findLeftmostSelect(SelectStmt *node); static SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt, static void insertSelectOptions(SelectStmt *stmt,
@ -131,9 +134,9 @@ static bool set_name_needs_quotes(const char *name);
AlterUserStmt, AlterUserSetStmt, AnalyzeStmt, AlterUserStmt, AlterUserSetStmt, AnalyzeStmt,
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt, ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateDomainStmt, CreateGroupStmt, CreatePLangStmt, CopyStmt, CreateAsStmt, CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt, CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateAssertStmt, CreateTrigStmt,
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt, CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt, DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropAssertStmt, DropTrigStmt,
DropRuleStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt, DropRuleStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt, GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt, NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
@ -273,14 +276,15 @@ static bool set_name_needs_quotes(const char *name);
%type <str> opt_charset, opt_collate %type <str> opt_charset, opt_collate
%type <str> opt_float %type <str> opt_float
%type <ival> opt_numeric, opt_decimal %type <ival> opt_numeric, opt_decimal
%type <boolean> opt_varying, opt_timezone, opt_timezone_x %type <boolean> opt_varying, opt_timezone
%type <ival> Iconst %type <ival> Iconst
%type <str> Sconst, comment_text %type <str> Sconst, comment_text
%type <str> UserId, opt_boolean, var_value, ColId_or_Sconst %type <str> UserId, opt_boolean, ColId_or_Sconst
%type <list> var_list
%type <str> ColId, ColLabel, type_name, func_name_keyword %type <str> ColId, ColLabel, type_name, func_name_keyword
%type <str> col_name_keyword, unreserved_keyword, reserved_keyword %type <str> col_name_keyword, unreserved_keyword, reserved_keyword
%type <node> zone_value %type <node> var_value, zone_value
%type <node> TableConstraint %type <node> TableConstraint
%type <list> ColQualList %type <list> ColQualList
@ -340,7 +344,7 @@ static bool set_name_needs_quotes(const char *name);
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
/* Keywords (in SQL99 reserved words) */ /* Keywords (in SQL99 reserved words) */
%token CHAIN, CHARACTERISTICS, %token ASSERTION, CHAIN, CHARACTERISTICS,
DEFERRABLE, DEFERRED, DEFERRABLE, DEFERRED,
IMMEDIATE, INITIALLY, INOUT, IMMEDIATE, INITIALLY, INOUT,
OFF, OUT, OFF, OUT,
@ -458,6 +462,7 @@ stmt : AlterDatabaseSetStmt
| CreateGroupStmt | CreateGroupStmt
| CreateSeqStmt | CreateSeqStmt
| CreatePLangStmt | CreatePLangStmt
| CreateAssertStmt
| CreateTrigStmt | CreateTrigStmt
| CreateUserStmt | CreateUserStmt
| ClusterStmt | ClusterStmt
@ -468,6 +473,7 @@ stmt : AlterDatabaseSetStmt
| CommentStmt | CommentStmt
| DropGroupStmt | DropGroupStmt
| DropPLangStmt | DropPLangStmt
| DropAssertStmt
| DropTrigStmt | DropTrigStmt
| DropRuleStmt | DropRuleStmt
| DropUserStmt | DropUserStmt
@ -812,6 +818,7 @@ schema_stmt: CreateStmt
| ViewStmt | ViewStmt
; ;
/***************************************************************************** /*****************************************************************************
* *
* Set PG internal variable * Set PG internal variable
@ -821,20 +828,18 @@ schema_stmt: CreateStmt
* *
*****************************************************************************/ *****************************************************************************/
VariableSetStmt: SET ColId TO var_value VariableSetStmt: SET ColId TO var_list
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = $2; n->name = $2;
if ($4 != NULL) n->args = $4;
n->args = makeList1(makeStringConst($4, NULL));
$$ = (Node *) n; $$ = (Node *) n;
} }
| SET ColId '=' var_value | SET ColId '=' var_list
{ {
VariableSetStmt *n = makeNode(VariableSetStmt); VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = $2; n->name = $2;
if ($4 != NULL) n->args = $4;
n->args = makeList1(makeStringConst($4, NULL));
$$ = (Node *) n; $$ = (Node *) n;
} }
| SET TIME ZONE zone_value | SET TIME ZONE zone_value
@ -876,69 +881,24 @@ VariableSetStmt: SET ColId TO var_value
} }
; ;
opt_level: READ COMMITTED { $$ = "read committed"; } var_list: var_value
| SERIALIZABLE { $$ = "serializable"; } { $$ = makeList1($1); }
| var_list ',' var_value
{ $$ = lappend($1, $3); }
| DEFAULT
{ $$ = NIL; }
; ;
var_value: opt_boolean { $$ = $1; } var_value: opt_boolean
| SCONST { $$ = $1; } { $$ = makeStringConst($1, NULL); }
| ICONST | ColId_or_Sconst
{ { $$ = makeStringConst($1, NULL); }
char buf[64]; | NumericOnly
sprintf(buf, "%d", $1); { $$ = makeAConst($1); }
$$ = pstrdup(buf); ;
}
| '-' ICONST
{
char buf[64];
sprintf(buf, "%d", -($2));
$$ = pstrdup(buf);
}
| FCONST { $$ = $1; }
| '-' FCONST
{
char * s = palloc(strlen($2)+2);
s[0] = '-';
strcpy(s + 1, $2);
$$ = s;
}
| name_list
{
List *n;
int slen = 0;
char *result;
/* List of words? Then concatenate together */ opt_level: READ COMMITTED { $$ = "read committed"; }
if ($1 == NIL) | SERIALIZABLE { $$ = "serializable"; }
elog(ERROR, "SET must have at least one argument");
/* compute space needed; allow for quotes and comma */
foreach (n, $1)
{
Value *p = (Value *) lfirst(n);
Assert(IsA(p, String));
slen += (strlen(p->val.str) + 3);
}
result = palloc(slen + 1);
*result = '\0';
foreach (n, $1)
{
Value *p = (Value *) lfirst(n);
if (set_name_needs_quotes(p->val.str))
{
strcat(result, "\"");
strcat(result, p->val.str);
strcat(result, "\"");
}
else
strcat(result, p->val.str);
strcat(result, ",");
}
/* remove the trailing comma from the last element */
*(result+strlen(result)-1) = '\0';
$$ = result;
}
| DEFAULT { $$ = NULL; }
; ;
opt_boolean: TRUE_P { $$ = "true"; } opt_boolean: TRUE_P { $$ = "true"; }
@ -949,13 +909,20 @@ opt_boolean: TRUE_P { $$ = "true"; }
/* Timezone values can be: /* Timezone values can be:
* - a string such as 'pst8pdt' * - a string such as 'pst8pdt'
* - a column identifier such as "pst8pdt"
* - an integer or floating point number * - an integer or floating point number
* - a time interval per SQL99 * - a time interval per SQL99
* ConstInterval and ColId give shift/reduce errors,
* so use IDENT and reject anything which is a reserved word.
*/ */
zone_value: Sconst zone_value: Sconst
{ {
$$ = makeStringConst($1, NULL); $$ = makeStringConst($1, NULL);
} }
| IDENT
{
$$ = makeStringConst($1, NULL);
}
| ConstInterval Sconst opt_interval | ConstInterval Sconst opt_interval
{ {
A_Const *n = (A_Const *) makeStringConst($2, $1); A_Const *n = (A_Const *) makeStringConst($2, $1);
@ -970,6 +937,9 @@ zone_value: Sconst
| ConstInterval '(' Iconst ')' Sconst opt_interval | ConstInterval '(' Iconst ')' Sconst opt_interval
{ {
A_Const *n = (A_Const *) makeStringConst($5, $1); A_Const *n = (A_Const *) makeStringConst($5, $1);
if (($3 < 0) || ($3 > MAX_INTERVAL_PRECISION))
elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
$3, 0, MAX_INTERVAL_PRECISION);
if ($6 != -1) if ($6 != -1)
{ {
if (($6 & ~(MASK(HOUR) | MASK(MINUTE))) != 0) if (($6 & ~(MASK(HOUR) | MASK(MINUTE))) != 0)
@ -983,26 +953,7 @@ zone_value: Sconst
$$ = (Node *)n; $$ = (Node *)n;
} }
| FCONST | NumericOnly { $$ = makeAConst($1); }
{
$$ = makeFloatConst($1);
}
| '-' FCONST
{
$$ = doNegate(makeFloatConst($2));
}
| ICONST
{
char buf[64];
sprintf(buf, "%d", $1);
$$ = makeFloatConst(pstrdup(buf));
}
| '-' ICONST
{
char buf[64];
sprintf(buf, "%d", $2);
$$ = doNegate(makeFloatConst(pstrdup(buf)));
}
| DEFAULT { $$ = NULL; } | DEFAULT { $$ = NULL; }
| LOCAL { $$ = NULL; } | LOCAL { $$ = NULL; }
; ;
@ -2072,6 +2023,42 @@ DropTrigStmt: DROP TRIGGER name ON qualified_name
; ;
/*****************************************************************************
*
* QUERIES :
* CREATE ASSERTION ...
* DROP ASSERTION ...
*
*****************************************************************************/
CreateAssertStmt: CREATE ASSERTION name
CHECK '(' a_expr ')' ConstraintAttributeSpec
{
CreateTrigStmt *n = makeNode(CreateTrigStmt);
n->trigname = $3;
n->args = makeList1($6);
n->isconstraint = TRUE;
n->deferrable = ($8 & 1) != 0;
n->initdeferred = ($8 & 2) != 0;
elog(ERROR, "CREATE ASSERTION is not yet supported");
$$ = (Node *)n;
}
;
DropAssertStmt: DROP ASSERTION name
{
DropPropertyStmt *n = makeNode(DropPropertyStmt);
n->relation = NULL;
n->property = $3;
n->removeType = DROP_TRIGGER;
elog(ERROR, "DROP ASSERTION is not yet supported");
$$ = (Node *) n;
}
;
/***************************************************************************** /*****************************************************************************
* *
* QUERY : * QUERY :
@ -4311,6 +4298,9 @@ SimpleTypename: ConstTypename
| ConstInterval '(' Iconst ')' opt_interval | ConstInterval '(' Iconst ')' opt_interval
{ {
$$ = $1; $$ = $1;
if (($3 < 0) || ($3 > MAX_INTERVAL_PRECISION))
elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
$3, 0, MAX_INTERVAL_PRECISION);
$$->typmod = ((($5 & 0x7FFF) << 16) | $3); $$->typmod = ((($5 & 0x7FFF) << 16) | $3);
} }
| type_name attrs | type_name attrs
@ -4547,7 +4537,7 @@ opt_collate: COLLATE ColId { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; } | /*EMPTY*/ { $$ = NULL; }
; ;
ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone
{ {
if ($5) if ($5)
$$ = makeTypeName(xlateSqlType("timestamptz")); $$ = makeTypeName(xlateSqlType("timestamptz"));
@ -4557,12 +4547,12 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
* - thomas 2001-09-06 * - thomas 2001-09-06
*/ */
$$->timezone = $5; $$->timezone = $5;
if (($3 < 0) || ($3 > 13)) if (($3 < 0) || ($3 > MAX_TIMESTAMP_PRECISION))
elog(ERROR, "TIMESTAMP(%d)%s precision must be between %d and %d", elog(ERROR, "TIMESTAMP(%d)%s precision must be between %d and %d",
$3, ($5 ? " WITH TIME ZONE": ""), 0, 13); $3, ($5 ? " WITH TIME ZONE": ""), 0, MAX_TIMESTAMP_PRECISION);
$$->typmod = $3; $$->typmod = $3;
} }
| TIMESTAMP opt_timezone_x | TIMESTAMP opt_timezone
{ {
if ($2) if ($2)
$$ = makeTypeName(xlateSqlType("timestamptz")); $$ = makeTypeName(xlateSqlType("timestamptz"));
@ -4587,9 +4577,9 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
$$ = makeTypeName(xlateSqlType("timetz")); $$ = makeTypeName(xlateSqlType("timetz"));
else else
$$ = makeTypeName(xlateSqlType("time")); $$ = makeTypeName(xlateSqlType("time"));
if (($3 < 0) || ($3 > 13)) if (($3 < 0) || ($3 > MAX_TIME_PRECISION))
elog(ERROR, "TIME(%d)%s precision must be between %d and %d", elog(ERROR, "TIME(%d)%s precision must be between %d and %d",
$3, ($5 ? " WITH TIME ZONE": ""), 0, 13); $3, ($5 ? " WITH TIME ZONE": ""), 0, MAX_TIME_PRECISION);
$$->typmod = $3; $$->typmod = $3;
} }
| TIME opt_timezone | TIME opt_timezone
@ -4612,16 +4602,6 @@ ConstInterval: INTERVAL
} }
; ;
/* XXX Make the default be WITH TIME ZONE for 7.2 to help with database upgrades
* but revert this back to WITHOUT TIME ZONE for 7.3.
* Do this by simply reverting opt_timezone_x to opt_timezone - thomas 2001-09-06
*/
opt_timezone_x: WITH TIME ZONE { $$ = TRUE; }
| WITHOUT TIME ZONE { $$ = FALSE; }
| /*EMPTY*/ { $$ = TRUE; }
;
opt_timezone: WITH TIME ZONE { $$ = TRUE; } opt_timezone: WITH TIME ZONE { $$ = TRUE; }
| WITHOUT TIME ZONE { $$ = FALSE; } | WITHOUT TIME ZONE { $$ = FALSE; }
| /*EMPTY*/ { $$ = FALSE; } | /*EMPTY*/ { $$ = FALSE; }
@ -5293,9 +5273,9 @@ c_expr: columnref
s->val.val.str = "now"; s->val.val.str = "now";
s->typename = makeTypeName(xlateSqlType("text")); s->typename = makeTypeName(xlateSqlType("text"));
d = makeTypeName(xlateSqlType("timetz")); d = makeTypeName(xlateSqlType("timetz"));
if (($3 < 0) || ($3 > 13)) if (($3 < 0) || ($3 > MAX_TIME_PRECISION))
elog(ERROR, "CURRENT_TIME(%d) precision must be between %d and %d", elog(ERROR, "CURRENT_TIME(%d) precision must be between %d and %d",
$3, 0, 13); $3, 0, MAX_TIME_PRECISION);
d->typmod = $3; d->typmod = $3;
$$ = (Node *)makeTypeCast((Node *)s, d); $$ = (Node *)makeTypeCast((Node *)s, d);
@ -5337,9 +5317,9 @@ c_expr: columnref
s->typename = makeTypeName(xlateSqlType("text")); s->typename = makeTypeName(xlateSqlType("text"));
d = makeTypeName(xlateSqlType("timestamptz")); d = makeTypeName(xlateSqlType("timestamptz"));
if (($3 < 0) || ($3 > 13)) if (($3 < 0) || ($3 > MAX_TIMESTAMP_PRECISION))
elog(ERROR, "CURRENT_TIMESTAMP(%d) precision must be between %d and %d", elog(ERROR, "CURRENT_TIMESTAMP(%d) precision must be between %d and %d",
$3, 0, 13); $3, 0, MAX_TIMESTAMP_PRECISION);
d->typmod = $3; d->typmod = $3;
$$ = (Node *)makeTypeCast((Node *)s, d); $$ = (Node *)makeTypeCast((Node *)s, d);
@ -5748,8 +5728,12 @@ target_el: a_expr AS ColLabel
} }
; ;
/* Target list as found in UPDATE table SET ... */ /* Target list as found in UPDATE table SET ...
| '(' row_ ')' = '(' row_ ')'
{
$$ = NULL;
}
*/
update_target_list: update_target_list ',' update_target_el update_target_list: update_target_list ',' update_target_el
{ $$ = lappend($1,$3); } { $$ = lappend($1,$3); }
| update_target_el | update_target_el
@ -5911,8 +5895,10 @@ AexprConst: Iconst
n->val.type = T_String; n->val.type = T_String;
n->val.val.str = $5; n->val.val.str = $5;
/* precision specified, and fields may be... */ /* precision specified, and fields may be... */
if (($3 < 0) || ($3 > MAX_INTERVAL_PRECISION))
elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
$3, 0, MAX_INTERVAL_PRECISION);
n->typename->typmod = ((($6 & 0x7FFF) << 16) | $3); n->typename->typmod = ((($6 & 0x7FFF) << 16) | $3);
$$ = (Node *)n; $$ = (Node *)n;
} }
| PARAM opt_indirection | PARAM opt_indirection
@ -6013,6 +5999,7 @@ unreserved_keyword:
| AFTER { $$ = "after"; } | AFTER { $$ = "after"; }
| AGGREGATE { $$ = "aggregate"; } | AGGREGATE { $$ = "aggregate"; }
| ALTER { $$ = "alter"; } | ALTER { $$ = "alter"; }
| ASSERTION { $$ = "assertion"; }
| AT { $$ = "at"; } | AT { $$ = "at"; }
| BACKWARD { $$ = "backward"; } | BACKWARD { $$ = "backward"; }
| BEFORE { $$ = "before"; } | BEFORE { $$ = "before"; }
@ -6357,6 +6344,17 @@ makeStringConst(char *str, TypeName *typename)
return (Node *)n; return (Node *)n;
} }
static Node *
makeIntConst(int val)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = val;
n->typename = makeTypeName(xlateSqlType("integer"));
return (Node *)n;
}
static Node * static Node *
makeFloatConst(char *str) makeFloatConst(char *str)
{ {
@ -6369,6 +6367,30 @@ makeFloatConst(char *str)
return (Node *)n; return (Node *)n;
} }
static Node *
makeAConst(Value *v)
{
Node *n;
switch (v->type)
{
case T_Float:
n = makeFloatConst(v->val.str);
break;
case T_Integer:
n = makeIntConst(v->val.ival);
break;
case T_String:
default:
n = makeStringConst(v->val.str, NULL);
break;
}
return n;
}
/* makeRowExpr() /* makeRowExpr()
* Generate separate operator nodes for a single row descriptor expression. * Generate separate operator nodes for a single row descriptor expression.
* Perhaps this should go deeper in the parser someday... * Perhaps this should go deeper in the parser someday...

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.106 2002/04/21 00:26:43 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.107 2002/04/21 19:21:49 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -43,6 +43,7 @@ static ScanKeyword ScanKeywords[] = {
{"any", ANY}, {"any", ANY},
{"as", AS}, {"as", AS},
{"asc", ASC}, {"asc", ASC},
{"assertion", ASSERTION},
{"at", AT}, {"at", AT},
{"authorization", AUTHORIZATION}, {"authorization", AUTHORIZATION},
{"backward", BACKWARD}, {"backward", BACKWARD},