mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +03:00
Implement SQL99 OVERLAY(). Allows substitution of a substring in a string.
Implement SQL99 SIMILAR TO as a synonym for our existing operator "~". Implement SQL99 regular expression SUBSTRING(string FROM pat FOR escape). Extend the definition to make the FOR clause optional. Define textregexsubstr() to actually implement this feature. Update the regression test to include these new string features. All tests pass. Rename the regular expression support routines from "pg95_xxx" to "pg_xxx". Define CREATE CHARACTER SET in the parser per SQL99. No implementation yet.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.320 2002/06/11 13:40:50 wieck Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.321 2002/06/11 15:41:37 thomas Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -227,10 +227,10 @@ static void doNegateFloat(Value *v);
|
||||
%type <node> join_outer, join_qual
|
||||
%type <jtype> join_type
|
||||
|
||||
%type <list> extract_list, position_list
|
||||
%type <list> extract_list, overlay_list, position_list
|
||||
%type <list> substr_list, trim_list
|
||||
%type <ival> opt_interval
|
||||
%type <node> substr_from, substr_for
|
||||
%type <node> overlay_placing, substr_from, substr_for
|
||||
|
||||
%type <boolean> opt_binary, opt_using, opt_instead, opt_cursor
|
||||
%type <boolean> opt_with_copy, index_opt_unique, opt_verbose, opt_full
|
||||
@@ -336,7 +336,7 @@ static void doNegateFloat(Value *v);
|
||||
FALSE_P, FETCH, FLOAT_P, FOR, FORCE, FOREIGN, FORWARD, FREEZE, FROM,
|
||||
FULL, FUNCTION,
|
||||
|
||||
GLOBAL, GRANT, GROUP_P,
|
||||
GET, GLOBAL, GRANT, GROUP_P,
|
||||
HANDLER, HAVING, HOUR_P,
|
||||
|
||||
ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT, INDEX, INHERITS,
|
||||
@@ -356,16 +356,16 @@ static void doNegateFloat(Value *v);
|
||||
NUMERIC,
|
||||
|
||||
OF, OFF, OFFSET, OIDS, OLD, ON, ONLY, OPERATOR, OPTION, OR, ORDER,
|
||||
OUT_P, OUTER_P, OVERLAPS, OWNER,
|
||||
OUT_P, OUTER_P, OVERLAPS, OVERLAY, OWNER,
|
||||
|
||||
PARTIAL, PASSWORD, PATH_P, PENDANT, POSITION, PRECISION, PRIMARY,
|
||||
PARTIAL, PASSWORD, PATH_P, PENDANT, PLACING, POSITION, PRECISION, PRIMARY,
|
||||
PRIOR, PRIVILEGES, PROCEDURE, PROCEDURAL,
|
||||
|
||||
READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE, RESET,
|
||||
RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW, RULE,
|
||||
|
||||
SCHEMA, SCROLL, SECOND_P, SECURITY, SELECT, SEQUENCE, SERIALIZABLE,
|
||||
SESSION, SESSION_USER, SET, SETOF, SHARE, SHOW, SMALLINT, SOME,
|
||||
SESSION, SESSION_USER, SET, SETOF, SHARE, SHOW, SIMILAR, SMALLINT, SOME,
|
||||
STABLE, START, STATEMENT, STATISTICS, STDIN, STDOUT, STORAGE, STRICT,
|
||||
SUBSTRING, SYSID,
|
||||
|
||||
@@ -402,7 +402,7 @@ static void doNegateFloat(Value *v);
|
||||
%right NOT
|
||||
%right '='
|
||||
%nonassoc '<' '>'
|
||||
%nonassoc LIKE ILIKE
|
||||
%nonassoc LIKE ILIKE SIMILAR
|
||||
%nonassoc ESCAPE
|
||||
%nonassoc OVERLAPS
|
||||
%nonassoc BETWEEN
|
||||
@@ -420,6 +420,7 @@ static void doNegateFloat(Value *v);
|
||||
%right UMINUS
|
||||
%left '[' ']'
|
||||
%left '(' ')'
|
||||
%left COLLATE
|
||||
%left TYPECAST
|
||||
%left '.'
|
||||
%%
|
||||
@@ -2139,6 +2140,14 @@ DefineStmt: CREATE AGGREGATE func_name definition
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE CHARACTER SET opt_as any_name GET definition opt_collate
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->defType = CHARACTER;
|
||||
n->defnames = $5;
|
||||
n->definition = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
definition: '(' def_list ')' { $$ = $2; }
|
||||
@@ -4978,9 +4987,18 @@ qual_all_Op: all_Op
|
||||
* it's factored out just to eliminate redundant coding.
|
||||
*/
|
||||
a_expr: c_expr
|
||||
{ $$ = $1; }
|
||||
{ $$ = $1; }
|
||||
| a_expr TYPECAST Typename
|
||||
{ $$ = makeTypeCast($1, $3); }
|
||||
| a_expr COLLATE ColId
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName($3);
|
||||
n->args = makeList1($1);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| a_expr AT TIME ZONE c_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
@@ -5088,6 +5106,30 @@ a_expr: c_expr
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n);
|
||||
}
|
||||
|
||||
| a_expr SIMILAR TO a_expr %prec SIMILAR
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "~", $1, $4); }
|
||||
| a_expr SIMILAR TO a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = makeList2($4, $6);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "~", $1, (Node *) n);
|
||||
}
|
||||
| a_expr NOT SIMILAR TO a_expr %prec SIMILAR
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~", $1, $5); }
|
||||
| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("like_escape");
|
||||
n->args = makeList2($5, $7);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "!~", $1, (Node *) n);
|
||||
}
|
||||
|
||||
/* NullTest clause
|
||||
* Define SQL92-style Null test clause.
|
||||
* Allow two forms described in the standard:
|
||||
@@ -5568,6 +5610,20 @@ c_expr: columnref
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| OVERLAY '(' overlay_list ')'
|
||||
{
|
||||
/* overlay(A PLACING B FROM C FOR D) is converted to
|
||||
* substring(A, 1, C-1) || B || substring(A, C+1, C+D)
|
||||
* overlay(A PLACING B FROM C) is converted to
|
||||
* substring(A, 1, C-1) || B || substring(A, C+1, C+char_length(B))
|
||||
*/
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = SystemFuncName("overlay");
|
||||
n->args = $3;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| POSITION '(' position_list ')'
|
||||
{
|
||||
/* position(A in B) is converted to position(B, A) */
|
||||
@@ -5706,6 +5762,25 @@ extract_arg: IDENT { $$ = $1; }
|
||||
| SCONST { $$ = $1; }
|
||||
;
|
||||
|
||||
/* OVERLAY() arguments
|
||||
* SQL99 defines the OVERLAY() function:
|
||||
* o overlay(text placing text from int for int)
|
||||
* o overlay(text placing text from int)
|
||||
*/
|
||||
overlay_list: a_expr overlay_placing substr_from substr_for
|
||||
{
|
||||
$$ = makeList4($1, $2, $3, $4);
|
||||
}
|
||||
| a_expr overlay_placing substr_from
|
||||
{
|
||||
$$ = makeList3($1, $2, $3);
|
||||
}
|
||||
;
|
||||
|
||||
overlay_placing: PLACING a_expr
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
/* position_list uses b_expr not a_expr to avoid conflict with general IN */
|
||||
|
||||
position_list: b_expr IN_P b_expr
|
||||
@@ -6259,6 +6334,7 @@ unreserved_keyword:
|
||||
| FORCE
|
||||
| FORWARD
|
||||
| FUNCTION
|
||||
| GET
|
||||
| GLOBAL
|
||||
| HANDLER
|
||||
| HOUR_P
|
||||
@@ -6404,6 +6480,7 @@ col_name_keyword:
|
||||
| NONE
|
||||
| NULLIF
|
||||
| NUMERIC
|
||||
| OVERLAY
|
||||
| POSITION
|
||||
| REAL
|
||||
| SETOF
|
||||
@@ -6423,7 +6500,7 @@ col_name_keyword:
|
||||
*
|
||||
* Do not include POSITION, SUBSTRING, etc here since they have explicit
|
||||
* productions in a_expr to support the goofy SQL9x argument syntax.
|
||||
* - thomas 2000-11-28
|
||||
* - thomas 2000-11-28
|
||||
*/
|
||||
func_name_keyword:
|
||||
AUTHORIZATION
|
||||
@@ -6445,6 +6522,7 @@ func_name_keyword:
|
||||
| OUTER_P
|
||||
| OVERLAPS
|
||||
| RIGHT
|
||||
| SIMILAR
|
||||
| VERBOSE
|
||||
;
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.112 2002/06/11 13:40:51 wieck Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.113 2002/06/11 15:41:37 thomas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -129,6 +129,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"from", FROM},
|
||||
{"full", FULL},
|
||||
{"function", FUNCTION},
|
||||
{"get", GET},
|
||||
{"global", GLOBAL},
|
||||
{"grant", GRANT},
|
||||
{"group", GROUP_P},
|
||||
@@ -211,11 +212,13 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"out", OUT_P},
|
||||
{"outer", OUTER_P},
|
||||
{"overlaps", OVERLAPS},
|
||||
{"overlay", OVERLAY},
|
||||
{"owner", OWNER},
|
||||
{"partial", PARTIAL},
|
||||
{"password", PASSWORD},
|
||||
{"path", PATH_P},
|
||||
{"pendant", PENDANT},
|
||||
{"placing", PLACING},
|
||||
{"position", POSITION},
|
||||
{"precision", PRECISION},
|
||||
{"primary", PRIMARY},
|
||||
@@ -251,6 +254,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"setof", SETOF},
|
||||
{"share", SHARE},
|
||||
{"show", SHOW},
|
||||
{"similar", SIMILAR},
|
||||
{"smallint", SMALLINT},
|
||||
{"some", SOME},
|
||||
{"stable", STABLE},
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.94 2002/05/02 18:44:10 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.95 2002/06/11 15:41:37 thomas Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -92,14 +92,14 @@ unsigned char unescape_single_char(unsigned char c);
|
||||
* We use exclusive states for quoted strings, extended comments,
|
||||
* and to eliminate parsing troubles for numeric strings.
|
||||
* Exclusive states:
|
||||
* <xbit> bit string literal
|
||||
* <xb> bit string literal
|
||||
* <xc> extended C-style comments - thomas 1997-07-12
|
||||
* <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
|
||||
* <xh> hexadecimal numeric string - thomas 1997-11-16
|
||||
* <xq> quoted strings - thomas 1997-07-30
|
||||
*/
|
||||
|
||||
%x xbit
|
||||
%x xb
|
||||
%x xc
|
||||
%x xd
|
||||
%x xh
|
||||
@@ -107,10 +107,10 @@ unsigned char unescape_single_char(unsigned char c);
|
||||
|
||||
/* Bit string
|
||||
*/
|
||||
xbitstart [bB]{quote}
|
||||
xbitstop {quote}
|
||||
xbitinside [^']*
|
||||
xbitcat {quote}{whitespace_with_newline}{quote}
|
||||
xbstart [bB]{quote}
|
||||
xbstop {quote}
|
||||
xbinside [^']*
|
||||
xbcat {quote}{whitespace_with_newline}{quote}
|
||||
|
||||
/* Hexadecimal number
|
||||
*/
|
||||
@@ -285,13 +285,13 @@ other .
|
||||
|
||||
<xc><<EOF>> { yyerror("unterminated /* comment"); }
|
||||
|
||||
{xbitstart} {
|
||||
{xbstart} {
|
||||
token_start = yytext;
|
||||
BEGIN(xbit);
|
||||
BEGIN(xb);
|
||||
startlit();
|
||||
addlitchar('b');
|
||||
}
|
||||
<xbit>{xbitstop} {
|
||||
<xb>{xbstop} {
|
||||
BEGIN(INITIAL);
|
||||
if (literalbuf[strspn(literalbuf + 1, "01") + 1] != '\0')
|
||||
yyerror("invalid bit string input");
|
||||
@@ -299,14 +299,14 @@ other .
|
||||
return BITCONST;
|
||||
}
|
||||
<xh>{xhinside} |
|
||||
<xbit>{xbitinside} {
|
||||
<xb>{xbinside} {
|
||||
addlit(yytext, yyleng);
|
||||
}
|
||||
<xh>{xhcat} |
|
||||
<xbit>{xbitcat} {
|
||||
<xb>{xbcat} {
|
||||
/* ignore */
|
||||
}
|
||||
<xbit><<EOF>> { yyerror("unterminated bit string literal"); }
|
||||
<xb><<EOF>> { yyerror("unterminated bit string literal"); }
|
||||
|
||||
{xhstart} {
|
||||
token_start = yytext;
|
||||
|
Reference in New Issue
Block a user