Commit 30ab107d authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Implement LIKE/ESCAPE. Change parser to use like()/notlike()

 rather than the "~~" operator; this made it easy to add ESCAPE features.
Implement ILIKE, NOT ILIKE, and the ESCAPE clause for them.
 afaict this is not MultiByte clean, but lots of other stuff isn't either.
Fix up underlying support code for LIKE/NOT LIKE.
 Things should be faster and does not require internal string copying.
Update regression test to add explicit checks for
 LIKE/NOT LIKE/ILIKE/NOT ILIKE.
Remove colon and semi-colon operators as threatened in 7.0.
Implement SQL99 COMMIT/AND NO CHAIN.
 Throw elog(ERROR) on COMMIT/AND CHAIN per spec
 since we don't yet support it.
Implement SQL99 CREATE/DROP SCHEMA as equivalent to CREATE DATABASE.
 This is only a stopgap or demo since schemas will have another
 implementation soon.
Remove a few unused production rules to get rid of warnings
 which crept in on the last commit.
Fix up tabbing in some places by removing embedded spaces.
parent df402346
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.181 2000/07/30 22:13:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.182 2000/08/06 18:05:21 thomas Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -123,7 +123,7 @@ static void doNegateFloat(Value *v); ...@@ -123,7 +123,7 @@ static void doNegateFloat(Value *v);
AlterSchemaStmt, AlterTableStmt, ClosePortalStmt, AlterSchemaStmt, AlterTableStmt, ClosePortalStmt,
CopyStmt, CreateStmt, CreateAsStmt, CreateSchemaStmt, CreateSeqStmt, DefineStmt, DropStmt, CopyStmt, CreateStmt, CreateAsStmt, CreateSchemaStmt, CreateSeqStmt, DefineStmt, DropStmt,
TruncateStmt, CommentStmt, TruncateStmt, CommentStmt,
ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt, ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropSchemaStmt, DropTrigStmt,
CreatePLangStmt, DropPLangStmt, CreatePLangStmt, DropPLangStmt,
IndexStmt, ListenStmt, UnlistenStmt, LockStmt, OptimizableStmt, IndexStmt, ListenStmt, UnlistenStmt, LockStmt, OptimizableStmt,
ProcedureStmt, ReindexStmt, RemoveAggrStmt, RemoveOperStmt, ProcedureStmt, ReindexStmt, RemoveAggrStmt, RemoveOperStmt,
...@@ -191,7 +191,7 @@ static void doNegateFloat(Value *v); ...@@ -191,7 +191,7 @@ static void doNegateFloat(Value *v);
%type <list> for_update_clause, update_list %type <list> for_update_clause, update_list
%type <boolean> opt_all %type <boolean> opt_all
%type <boolean> opt_table %type <boolean> opt_table
%type <boolean> opt_trans %type <boolean> opt_chain, opt_trans
%type <jexpr> from_expr, join_clause, join_expr %type <jexpr> from_expr, join_clause, join_expr
%type <jexpr> join_clause_with_union, join_expr_with_union %type <jexpr> join_clause_with_union, join_expr_with_union
...@@ -252,7 +252,7 @@ static void doNegateFloat(Value *v); ...@@ -252,7 +252,7 @@ static void doNegateFloat(Value *v);
%type <typnam> Typename, SimpleTypename, ConstTypename %type <typnam> Typename, SimpleTypename, ConstTypename
Generic, Numeric, Geometric, Character, ConstDatetime, ConstInterval, Bit Generic, Numeric, Geometric, Character, ConstDatetime, ConstInterval, Bit
%type <str> typename, generic, numeric, geometric, character, datetime, bit %type <str> generic, character, datetime, bit
%type <str> extract_arg %type <str> extract_arg
%type <str> opt_charset, opt_collate %type <str> opt_charset, opt_collate
%type <str> opt_float %type <str> opt_float
...@@ -302,7 +302,7 @@ static void doNegateFloat(Value *v); ...@@ -302,7 +302,7 @@ static void doNegateFloat(Value *v);
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC,
DISTINCT, DOUBLE, DROP, DISTINCT, DOUBLE, DROP,
ELSE, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT, ELSE, END_TRANS, ESCAPE, EXCEPT, EXECUTE, EXISTS, EXTRACT,
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL, FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
GLOBAL, GRANT, GROUP, HAVING, HOUR_P, GLOBAL, GRANT, GROUP, HAVING, HOUR_P,
IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS, IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS,
...@@ -320,7 +320,7 @@ static void doNegateFloat(Value *v); ...@@ -320,7 +320,7 @@ static void doNegateFloat(Value *v);
WHEN, WHERE, WITH, WORK, YEAR_P, ZONE WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
/* Keywords (in SQL3 reserved words) */ /* Keywords (in SQL3 reserved words) */
%token CHARACTERISTICS, %token CHAIN, CHARACTERISTICS,
DEFERRABLE, DEFERRED, DEFERRABLE, DEFERRED,
IMMEDIATE, INITIALLY, INOUT, IMMEDIATE, INITIALLY, INOUT,
OFF, OUT, OFF, OUT,
...@@ -345,7 +345,7 @@ static void doNegateFloat(Value *v); ...@@ -345,7 +345,7 @@ static void doNegateFloat(Value *v);
DATABASE, DELIMITERS, DO, DATABASE, DELIMITERS, DO,
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND, EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
FORCE, FORWARD, FUNCTION, HANDLER, FORCE, FORWARD, FUNCTION, HANDLER,
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P, LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
MAXVALUE, MINVALUE, MODE, MOVE, MAXVALUE, MINVALUE, MODE, MOVE,
NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
...@@ -368,7 +368,7 @@ static void doNegateFloat(Value *v); ...@@ -368,7 +368,7 @@ static void doNegateFloat(Value *v);
%right NOT %right NOT
%right '=' %right '='
%nonassoc '<' '>' %nonassoc '<' '>'
%nonassoc LIKE %nonassoc LIKE ILIKE
%nonassoc OVERLAPS %nonassoc OVERLAPS
%nonassoc BETWEEN %nonassoc BETWEEN
%nonassoc IN %nonassoc IN
...@@ -382,13 +382,14 @@ static void doNegateFloat(Value *v); ...@@ -382,13 +382,14 @@ static void doNegateFloat(Value *v);
%left '^' %left '^'
%left '|' /* this is the relation union op, not logical or */ %left '|' /* this is the relation union op, not logical or */
/* Unary Operators */ /* Unary Operators */
%right ':' %right ':' /* delimiter for array ranges */
%left ';' /* end of statement or natural log */ %left ';' /* end of statement */
%right UMINUS %right UMINUS
%left '.' %left '.'
%left '[' ']' %left '[' ']'
%left TYPECAST %left TYPECAST
%left UNION INTERSECT EXCEPT %left UNION INTERSECT EXCEPT
%left ESCAPE
%% %%
/* /*
...@@ -432,6 +433,7 @@ stmt : AlterSchemaStmt ...@@ -432,6 +433,7 @@ stmt : AlterSchemaStmt
| ClusterStmt | ClusterStmt
| DefineStmt | DefineStmt
| DropStmt | DropStmt
| DropSchemaStmt
| TruncateStmt | TruncateStmt
| CommentStmt | CommentStmt
| DropGroupStmt | DropGroupStmt
...@@ -678,7 +680,16 @@ DropGroupStmt: DROP GROUP UserId ...@@ -678,7 +680,16 @@ DropGroupStmt: DROP GROUP UserId
CreateSchemaStmt: CREATE SCHEMA UserId CreateSchemaStmt: CREATE SCHEMA UserId
{ {
elog(ERROR, "CREATE SCHEMA not yet supported"); /* for now, just make this the same as CREATE DATABASE */
CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3;
n->dbpath = NULL;
#ifdef MULTIBYTE
n->encoding = GetTemplateEncoding();
#else
n->encoding = 0;
#endif
$$ = (Node *)n;
} }
; ;
...@@ -688,6 +699,13 @@ AlterSchemaStmt: ALTER SCHEMA UserId ...@@ -688,6 +699,13 @@ AlterSchemaStmt: ALTER SCHEMA UserId
} }
; ;
DropSchemaStmt: DROP SCHEMA UserId
{
DropdbStmt *n = makeNode(DropdbStmt);
n->dbname = $3;
$$ = (Node *)n;
}
/***************************************************************************** /*****************************************************************************
* *
...@@ -2648,7 +2666,7 @@ opt_force: FORCE { $$ = TRUE; } ...@@ -2648,7 +2666,7 @@ opt_force: FORCE { $$ = TRUE; }
*****************************************************************************/ *****************************************************************************/
RenameStmt: ALTER TABLE relation_name opt_inh_star RenameStmt: ALTER TABLE relation_name opt_inh_star
/* "*" deprecated */ /* "*" deprecated */
RENAME opt_column opt_name TO name RENAME opt_column opt_name TO name
{ {
RenameStmt *n = makeNode(RenameStmt); RenameStmt *n = makeNode(RenameStmt);
...@@ -2823,6 +2841,12 @@ TransactionStmt: ABORT_TRANS opt_trans ...@@ -2823,6 +2841,12 @@ TransactionStmt: ABORT_TRANS opt_trans
n->command = COMMIT; n->command = COMMIT;
$$ = (Node *)n; $$ = (Node *)n;
} }
| COMMIT opt_trans opt_chain
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = COMMIT;
$$ = (Node *)n;
}
| END_TRANS opt_trans | END_TRANS opt_trans
{ {
TransactionStmt *n = makeNode(TransactionStmt); TransactionStmt *n = makeNode(TransactionStmt);
...@@ -2835,6 +2859,12 @@ TransactionStmt: ABORT_TRANS opt_trans ...@@ -2835,6 +2859,12 @@ TransactionStmt: ABORT_TRANS opt_trans
n->command = ROLLBACK; n->command = ROLLBACK;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ROLLBACK opt_trans opt_chain
{
TransactionStmt *n = makeNode(TransactionStmt);
n->command = ROLLBACK;
$$ = (Node *)n;
}
; ;
opt_trans: WORK { $$ = TRUE; } opt_trans: WORK { $$ = TRUE; }
...@@ -2842,6 +2872,19 @@ opt_trans: WORK { $$ = TRUE; } ...@@ -2842,6 +2872,19 @@ opt_trans: WORK { $$ = TRUE; }
| /*EMPTY*/ { $$ = TRUE; } | /*EMPTY*/ { $$ = TRUE; }
; ;
opt_chain: AND NO CHAIN
{ $$ = FALSE; }
| AND CHAIN
{
/* SQL99 asks that conforming dbs reject AND CHAIN
* if they don't support it. So we can't just ignore it.
* - thomas 2000-08-06
*/
elog(ERROR, "COMMIT/CHAIN not yet supported");
$$ = TRUE;
}
;
/***************************************************************************** /*****************************************************************************
* *
...@@ -2891,11 +2934,11 @@ LoadStmt: LOAD file_name ...@@ -2891,11 +2934,11 @@ LoadStmt: LOAD file_name
*****************************************************************************/ *****************************************************************************/
CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb_opt_encoding
{ {
CreatedbStmt *n; CreatedbStmt *n;
if ($5 == NULL && $6 == -1) if ($5 == NULL && $6 == -1)
elog(ERROR, "CREATE DATABASE WITH requires at least one option."); elog(ERROR, "CREATE DATABASE WITH requires at least one option.");
n = makeNode(CreatedbStmt); n = makeNode(CreatedbStmt);
n->dbname = $3; n->dbname = $3;
...@@ -2918,50 +2961,49 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb ...@@ -2918,50 +2961,49 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_location createdb
; ;
createdb_opt_location: LOCATION '=' Sconst { $$ = $3; } createdb_opt_location: LOCATION '=' Sconst { $$ = $3; }
| LOCATION '=' DEFAULT { $$ = NULL; } | LOCATION '=' DEFAULT { $$ = NULL; }
| /*EMPTY*/ { $$ = NULL; } | /*EMPTY*/ { $$ = NULL; }
; ;
createdb_opt_encoding: createdb_opt_encoding: ENCODING '=' Sconst
ENCODING '=' Sconst {
{
#ifdef MULTIBYTE #ifdef MULTIBYTE
int i; int i;
i = pg_char_to_encoding($3); i = pg_char_to_encoding($3);
if (i == -1) if (i == -1)
elog(ERROR, "%s is not a valid encoding name", $3); elog(ERROR, "%s is not a valid encoding name", $3);
$$ = i; $$ = i;
#else #else
elog(ERROR, "Multi-byte support is not enabled"); elog(ERROR, "Multi-byte support is not enabled");
#endif #endif
} }
| ENCODING '=' Iconst | ENCODING '=' Iconst
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
if (!pg_get_encent_by_encoding($3)) if (!pg_get_encent_by_encoding($3))
elog(ERROR, "%d is not a valid encoding code", $3); elog(ERROR, "%d is not a valid encoding code", $3);
$$ = $3; $$ = $3;
#else #else
elog(ERROR, "Multi-byte support is not enabled"); elog(ERROR, "Multi-byte support is not enabled");
#endif #endif
} }
| ENCODING '=' DEFAULT | ENCODING '=' DEFAULT
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
$$ = GetTemplateEncoding(); $$ = GetTemplateEncoding();
#else #else
$$ = 0; $$ = 0;
#endif #endif
} }
| /*EMPTY*/ | /*EMPTY*/
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
$$ = GetTemplateEncoding(); $$ = GetTemplateEncoding();
#else #else
$$= 0; $$= 0;
#endif #endif
} }
; ;
/***************************************************************************** /*****************************************************************************
...@@ -3255,7 +3297,7 @@ UpdateStmt: UPDATE opt_only relation_name ...@@ -3255,7 +3297,7 @@ UpdateStmt: UPDATE opt_only relation_name
where_clause where_clause
{ {
UpdateStmt *n = makeNode(UpdateStmt); UpdateStmt *n = makeNode(UpdateStmt);
n->inh = $2; n->inh = $2;
n->relname = $3; n->relname = $3;
n->targetList = $5; n->targetList = $5;
n->fromClause = $6; n->fromClause = $6;
...@@ -3353,7 +3395,7 @@ SelectStmt: select_clause sort_clause for_update_clause opt_select_limit ...@@ -3353,7 +3395,7 @@ SelectStmt: select_clause sort_clause for_update_clause opt_select_limit
List *select_list = NIL; List *select_list = NIL;
SelectStmt *first_select; SelectStmt *first_select;
bool intersect_present = FALSE, bool intersect_present = FALSE,
unionall_present = FALSE; unionall_present = FALSE;
/* Take the operator tree as an argument and create a /* Take the operator tree as an argument and create a
* list of all SelectStmt Nodes found in the tree. * list of all SelectStmt Nodes found in the tree.
...@@ -3429,21 +3471,21 @@ select_clause: '(' select_clause ')' ...@@ -3429,21 +3471,21 @@ select_clause: '(' select_clause ')'
| select_clause EXCEPT select_clause | select_clause EXCEPT select_clause
{ {
$$ = (Node *)makeA_Expr(AND,NULL,$1, $$ = (Node *)makeA_Expr(AND,NULL,$1,
makeA_Expr(NOT,NULL,NULL,$3)); makeA_Expr(NOT,NULL,NULL,$3));
} }
| select_clause UNION opt_all select_clause | select_clause UNION opt_all select_clause
{ {
if (IsA($4, SelectStmt)) if (IsA($4, SelectStmt))
{ {
SelectStmt *n = (SelectStmt *)$4; SelectStmt *n = (SelectStmt *)$4;
n->unionall = $3; n->unionall = $3;
/* NOTE: if UNION ALL appears with a parenthesized set /* NOTE: if UNION ALL appears with a parenthesized set
* operation to its right, the ALL is silently discarded. * operation to its right, the ALL is silently discarded.
* Should we generate an error instead? I think it may * Should we generate an error instead? I think it may
* be OK since ALL with UNION to its right is ignored * be OK since ALL with UNION to its right is ignored
* anyway... * anyway...
*/ */
} }
$$ = (Node *)makeA_Expr(OR,NULL,$1,$4); $$ = (Node *)makeA_Expr(OR,NULL,$1,$4);
} }
| select_clause INTERSECT select_clause | select_clause INTERSECT select_clause
...@@ -3899,21 +3941,21 @@ relation_expr: relation_name ...@@ -3899,21 +3941,21 @@ relation_expr: relation_name
$$->relname = $1; $$->relname = $1;
$$->inh = SQL_inheritance; $$->inh = SQL_inheritance;
} }
| relation_name '*' %prec '=' | relation_name '*' %prec '='
{ {
/* inheritance query */ /* inheritance query */
$$ = makeNode(RelExpr); $$ = makeNode(RelExpr);
$$->relname = $1; $$->relname = $1;
$$->inh = TRUE; $$->inh = TRUE;
} }
| ONLY relation_name %prec '=' | ONLY relation_name %prec '='
{ {
/* no inheritance */ /* no inheritance */
$$ = makeNode(RelExpr); $$ = makeNode(RelExpr);
$$->relname = $2; $$->relname = $2;
$$->inh = FALSE; $$->inh = FALSE;
} }
; ;
opt_array_bounds: '[' ']' opt_array_bounds opt_array_bounds: '[' ']' opt_array_bounds
{ $$ = lcons(makeInteger(-1), $3); } { $$ = lcons(makeInteger(-1), $3); }
...@@ -3975,14 +4017,6 @@ ConstTypename: Generic ...@@ -3975,14 +4017,6 @@ ConstTypename: Generic
| ConstDatetime | ConstDatetime
; ;
typename: generic { $$ = $1; }
| numeric { $$ = $1; }
| geometric { $$ = $1; }
| bit { $$ = $1; }
| character { $$ = $1; }
| datetime { $$ = $1; }
;
Generic: generic Generic: generic
{ {
$$ = makeNode(TypeName); $$ = makeNode(TypeName);
...@@ -4032,13 +4066,6 @@ Numeric: FLOAT opt_float ...@@ -4032,13 +4066,6 @@ Numeric: FLOAT opt_float
} }
; ;
numeric: FLOAT { $$ = xlateSqlType("float"); }
| DOUBLE PRECISION { $$ = xlateSqlType("float8"); }
| DECIMAL { $$ = xlateSqlType("decimal"); }
| DEC { $$ = xlateSqlType("decimal"); }
| NUMERIC { $$ = xlateSqlType("numeric"); }
;
Geometric: PATH_P Geometric: PATH_P
{ {
$$ = makeNode(TypeName); $$ = makeNode(TypeName);
...@@ -4047,9 +4074,6 @@ Geometric: PATH_P ...@@ -4047,9 +4074,6 @@ Geometric: PATH_P
} }
; ;
geometric: PATH_P { $$ = xlateSqlType("path"); }
;
opt_float: '(' Iconst ')' opt_float: '(' Iconst ')'
{ {
if ($2 < 1) if ($2 < 1)
...@@ -4435,16 +4459,6 @@ a_expr: c_expr ...@@ -4435,16 +4459,6 @@ a_expr: c_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); } { $$ = makeA_Expr(OP, "^", NULL, $2); }
| '|' a_expr | '|' a_expr
{ $$ = makeA_Expr(OP, "|", NULL, $2); } { $$ = makeA_Expr(OP, "|", NULL, $2); }
| ':' a_expr
{ $$ = makeA_Expr(OP, ":", NULL, $2);
elog(NOTICE, "The ':' operator is deprecated. Use exp(x) instead."
"\n\tThis operator will be removed in a future release.");
}
| ';' a_expr
{ $$ = makeA_Expr(OP, ";", NULL, $2);
elog(NOTICE, "The ';' operator is deprecated. Use ln(x) instead."
"\n\tThis operator will be removed in a future release.");
}
| a_expr '%' | a_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); } { $$ = makeA_Expr(OP, "%", $1, NULL); }
| a_expr '^' | a_expr '^'
...@@ -4499,9 +4513,77 @@ a_expr: c_expr ...@@ -4499,9 +4513,77 @@ a_expr: c_expr
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); } { $$ = makeA_Expr(NOT, NULL, NULL, $2); }
| a_expr LIKE a_expr | a_expr LIKE a_expr
{ $$ = makeA_Expr(OP, "~~", $1, $3); } {
FuncCall *n = makeNode(FuncCall);
n->funcname = "like";
n->args = makeList($1, $3, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "like";
n->args = makeList($1, $3, $5, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr NOT LIKE a_expr | a_expr NOT LIKE a_expr
{ $$ = makeA_Expr(OP, "!~~", $1, $4); } {
FuncCall *n = makeNode(FuncCall);
n->funcname = "notlike";
n->args = makeList($1, $4, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr NOT LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "notlike";
n->args = makeList($1, $4, $6, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr ILIKE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "ilike";
n->args = makeList($1, $3, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "ilike";
n->args = makeList($1, $3, $5, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr NOT ILIKE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "inotlike";
n->args = makeList($1, $4, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr NOT ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
n->funcname = "inotlike";
n->args = makeList($1, $4, $6, -1);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| a_expr ISNULL | a_expr ISNULL
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); } { $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
...@@ -4659,16 +4741,6 @@ b_expr: c_expr ...@@ -4659,16 +4741,6 @@ b_expr: c_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); } { $$ = makeA_Expr(OP, "^", NULL, $2); }
| '|' b_expr | '|' b_expr
{ $$ = makeA_Expr(OP, "|", NULL, $2); } { $$ = makeA_Expr(OP, "|", NULL, $2); }
| ':' b_expr
{ $$ = makeA_Expr(OP, ":", NULL, $2);
elog(NOTICE, "The ':' operator is deprecated. Use exp(x) instead."
"\n\tThis operator will be removed in a future release.");
}
| ';' b_expr
{ $$ = makeA_Expr(OP, ";", NULL, $2);
elog(NOTICE, "The ';' operator is deprecated. Use ln(x) instead."
"\n\tThis operator will be removed in a future release.");
}
| b_expr '%' | b_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); } { $$ = makeA_Expr(OP, "%", $1, NULL); }
| b_expr '^' | b_expr '^'
...@@ -5496,6 +5568,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; } ...@@ -5496,6 +5568,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
| BY { $$ = "by"; } | BY { $$ = "by"; }
| CACHE { $$ = "cache"; } | CACHE { $$ = "cache"; }
| CASCADE { $$ = "cascade"; } | CASCADE { $$ = "cascade"; }
| CHAIN { $$ = "chain"; }
| CLOSE { $$ = "close"; } | CLOSE { $$ = "close"; }
| COMMENT { $$ = "comment"; } | COMMENT { $$ = "comment"; }
| COMMIT { $$ = "commit"; } | COMMIT { $$ = "commit"; }
...@@ -5515,6 +5588,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; } ...@@ -5515,6 +5588,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
| DROP { $$ = "drop"; } | DROP { $$ = "drop"; }
| EACH { $$ = "each"; } | EACH { $$ = "each"; }
| ENCODING { $$ = "encoding"; } | ENCODING { $$ = "encoding"; }
| ESCAPE { $$ = "escape"; }
| EXCLUSIVE { $$ = "exclusive"; } | EXCLUSIVE { $$ = "exclusive"; }
| EXECUTE { $$ = "execute"; } | EXECUTE { $$ = "execute"; }
| FETCH { $$ = "fetch"; } | FETCH { $$ = "fetch"; }
...@@ -5661,6 +5735,7 @@ ColLabel: ColId { $$ = $1; } ...@@ -5661,6 +5735,7 @@ ColLabel: ColId { $$ = $1; }
| GLOBAL { $$ = "global"; } | GLOBAL { $$ = "global"; }
| GROUP { $$ = "group"; } | GROUP { $$ = "group"; }
| HAVING { $$ = "having"; } | HAVING { $$ = "having"; }
| ILIKE { $$ = "ilike"; }
| INITIALLY { $$ = "initially"; } | INITIALLY { $$ = "initially"; }
| IN { $$ = "in"; } | IN { $$ = "in"; }
| INNER_P { $$ = "inner"; } | INNER_P { $$ = "inner"; }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.79 2000/07/14 15:43:32 thomas Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.80 2000/08/06 18:05:22 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -55,6 +55,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -55,6 +55,7 @@ static ScanKeyword ScanKeywords[] = {
{"cascade", CASCADE}, {"cascade", CASCADE},
{"case", CASE}, {"case", CASE},
{"cast", CAST}, {"cast", CAST},
{"chain", CHAIN},
{"char", CHAR}, {"char", CHAR},
{"character", CHARACTER}, {"character", CHARACTER},
{"characteristics", CHARACTERISTICS}, {"characteristics", CHARACTERISTICS},
...@@ -101,6 +102,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -101,6 +102,7 @@ static ScanKeyword ScanKeywords[] = {
{"else", ELSE}, {"else", ELSE},
{"encoding", ENCODING}, {"encoding", ENCODING},
{"end", END_TRANS}, {"end", END_TRANS},
{"escape", ESCAPE},
{"except", EXCEPT}, {"except", EXCEPT},
{"exclusive", EXCLUSIVE}, {"exclusive", EXCLUSIVE},
{"execute", EXECUTE}, {"execute", EXECUTE},
...@@ -124,6 +126,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -124,6 +126,7 @@ static ScanKeyword ScanKeywords[] = {
{"handler", HANDLER}, {"handler", HANDLER},
{"having", HAVING}, {"having", HAVING},
{"hour", HOUR_P}, {"hour", HOUR_P},
{"ilike", ILIKE},
{"immediate", IMMEDIATE}, {"immediate", IMMEDIATE},
{"in", IN}, {"in", IN},
{"increment", INCREMENT}, {"increment", INCREMENT},
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.37 2000/07/07 21:12:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.38 2000/08/06 18:05:41 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,97 +20,222 @@ ...@@ -20,97 +20,222 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "utils/builtins.h" #include "utils/builtins.h"
static bool like(pg_wchar * text, pg_wchar * p);
#define LIKE_TRUE 1
#define LIKE_FALSE 0
#define LIKE_ABORT (-1)
static int MatchText(pg_wchar * t, int tlen, pg_wchar * p, int plen, char *e);
static int MatchTextLower(pg_wchar * t, int tlen, pg_wchar * p, int plen, char *e);
/* /*
* interface routines called by the function manager * interface routines called by the function manager
*/ */
/* Datum
fixedlen_like: namelike(PG_FUNCTION_ARGS)
{
Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
a generic fixed length like routine PG_RETURN_BOOL(MatchText(NameStr(*n), strlen(NameStr(*n)),
s - the string to match against (not necessarily null-terminated) VARDATA(p), (VARSIZE(p)-VARHDRSZ),
p - the pattern (as text*) NULL)
charlen - the length of the string == LIKE_TRUE);
*/ }
static bool
fixedlen_like(char *s, text *p, int charlen)
{
pg_wchar *sterm,
*pterm;
bool result;
int len;
/* be sure sterm is null-terminated */
#ifdef MULTIBYTE
sterm = (pg_wchar *) palloc((charlen + 1) * sizeof(pg_wchar));
(void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
#else
sterm = (char *) palloc(charlen + 1);
memcpy(sterm, s, charlen);
sterm[charlen] = '\0';
#endif
/* Datum
* p is a text, not a string so we have to make a string namenlike(PG_FUNCTION_ARGS)
* from the vl_data field of the struct. {
*/ Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
/* palloc the length of the text + the null character */ PG_RETURN_BOOL(MatchText(NameStr(*n), strlen(NameStr(*n)),
len = VARSIZE(p) - VARHDRSZ; VARDATA(p), (VARSIZE(p)-VARHDRSZ),
#ifdef MULTIBYTE NULL)
pterm = (pg_wchar *) palloc((len + 1) * sizeof(pg_wchar)); != LIKE_TRUE);
(void) pg_mb2wchar_with_len((unsigned char *) VARDATA(p), pterm, len); }
#else
pterm = (char *) palloc(len + 1);
memcpy(pterm, VARDATA(p), len);
*(pterm + len) = '\0';
#endif
/* do the regexp matching */ Datum
result = like(sterm, pterm); namelike_escape(PG_FUNCTION_ARGS)
{
Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
pfree(sterm); PG_RETURN_BOOL(MatchText(NameStr(*n), strlen(NameStr(*n)),
pfree(pterm); VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
== LIKE_TRUE);
}
return result; Datum
namenlike_escape(PG_FUNCTION_ARGS)
{
Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchText(NameStr(*n), strlen(NameStr(*n)),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
!= LIKE_TRUE);
} }
Datum Datum
namelike(PG_FUNCTION_ARGS) textlike(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(MatchText(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
== LIKE_TRUE);
}
Datum
textnlike(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(MatchText(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
!= LIKE_TRUE);
}
Datum
textlike_escape(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchText(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
== LIKE_TRUE);
}
Datum
textnlike_escape(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchText(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
!= LIKE_TRUE);
}
/*
* Case-insensitive versions
*/
Datum
inamelike(PG_FUNCTION_ARGS)
{ {
Name n = PG_GETARG_NAME(0); Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1); text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(fixedlen_like(NameStr(*n), p, strlen(NameStr(*n)))); PG_RETURN_BOOL(MatchTextLower(NameStr(*n), strlen(NameStr(*n)),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
== LIKE_TRUE);
} }
Datum Datum
namenlike(PG_FUNCTION_ARGS) inamenlike(PG_FUNCTION_ARGS)
{ {
Name n = PG_GETARG_NAME(0); Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1); text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(! fixedlen_like(NameStr(*n), p, strlen(NameStr(*n)))); PG_RETURN_BOOL(MatchTextLower(NameStr(*n), strlen(NameStr(*n)),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
!= LIKE_TRUE);
} }
Datum Datum
textlike(PG_FUNCTION_ARGS) inamelike_escape(PG_FUNCTION_ARGS)
{
Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchTextLower(NameStr(*n), strlen(NameStr(*n)),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
== LIKE_TRUE);
}
Datum
inamenlike_escape(PG_FUNCTION_ARGS)
{
Name n = PG_GETARG_NAME(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchTextLower(NameStr(*n), strlen(NameStr(*n)),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
!= LIKE_TRUE);
}
Datum
itextlike(PG_FUNCTION_ARGS)
{ {
text *s = PG_GETARG_TEXT_P(0); text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1); text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ)); PG_RETURN_BOOL(MatchTextLower(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
== LIKE_TRUE);
} }
Datum Datum
textnlike(PG_FUNCTION_ARGS) itextnlike(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
PG_RETURN_BOOL(MatchTextLower(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
NULL)
!= LIKE_TRUE);
}
Datum
itextlike_escape(PG_FUNCTION_ARGS)
{
text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(MatchTextLower(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
== LIKE_TRUE);
}
Datum
itextnlike_escape(PG_FUNCTION_ARGS)
{ {
text *s = PG_GETARG_TEXT_P(0); text *s = PG_GETARG_TEXT_P(0);
text *p = PG_GETARG_TEXT_P(1); text *p = PG_GETARG_TEXT_P(1);
text *e = PG_GETARG_TEXT_P(2);
PG_RETURN_BOOL(! fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ)); PG_RETURN_BOOL(MatchTextLower(VARDATA(s), (VARSIZE(s)-VARHDRSZ),
VARDATA(p), (VARSIZE(p)-VARHDRSZ),
((VARSIZE(e)-VARHDRSZ) > 0? VARDATA(e): NULL))
!= LIKE_TRUE);
} }
...@@ -136,12 +261,16 @@ textnlike(PG_FUNCTION_ARGS) ...@@ -136,12 +261,16 @@ textnlike(PG_FUNCTION_ARGS)
** LIKE <pattern> ESCAPE <escape character>. We are a small operation ** LIKE <pattern> ESCAPE <escape character>. We are a small operation
** so we force you to use '\'. - ay 7/95] ** so we force you to use '\'. - ay 7/95]
** **
** OK, we now support the SQL9x LIKE <pattern> ESCAPE <char> syntax.
** We should kill the backslash escaping mechanism since it is non-standard
** and undocumented afaik.
** The code is rewritten to avoid requiring null-terminated strings,
** which in turn allows us to leave out some memcpy() operations.
** This code should be faster and take less memory, but no promises...
** - thomas 2000-08-06
**
*/ */
#define LIKE_TRUE 1
#define LIKE_FALSE 0
#define LIKE_ABORT (-1)
/*-------------------- /*--------------------
* Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT. * Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
* *
...@@ -153,69 +282,97 @@ textnlike(PG_FUNCTION_ARGS) ...@@ -153,69 +282,97 @@ textnlike(PG_FUNCTION_ARGS)
* pattern either, so an upper-level % scan can stop scanning now. * pattern either, so an upper-level % scan can stop scanning now.
*-------------------- *--------------------
*/ */
#define NextChar(p, plen) (p)++, (plen)--
static int static int
DoMatch(pg_wchar * text, pg_wchar * p) MatchText(pg_wchar * t, int tlen, pg_wchar * p, int plen, char *e)
{ {
for (; *p && *text; text ++, p++) /* Fast path for match-everything pattern
* Include weird case of escape character as a percent sign or underscore,
* when presumably that wildcard character becomes a literal.
*/
if ((plen == 1) && (*p == '%')
&& ! ((e != NULL) && (*e == '%')))
return LIKE_TRUE;
while ((tlen > 0) && (plen > 0))
{ {
switch (*p) /* If an escape character was specified and we find it here in the pattern,
* then we'd better have an exact match for the next character.
*/
if ((e != NULL) && (*p == *e))
{ {
case '\\': NextChar(p, plen);
/* Literal match with following character. */ if ((plen <= 0) || (*t != *p))
p++; return LIKE_FALSE;
/* FALLTHROUGH */ }
default: else
if (*text !=*p) {
return LIKE_FALSE; switch (*p)
break; {
case '_': case '\\':
/* Match any single character. */ /* Literal match with following character. */
break; NextChar(p, plen);
case '%': /* FALLTHROUGH */
/* %% is the same as % according to the SQL standard */ default:
/* Advance past all %'s */ if (*t != *p)
while (*p == '%') return LIKE_FALSE;
p++; break;
/* Trailing percent matches everything. */ case '_':
if (*p == '\0') /* Match any single character. */
return LIKE_TRUE; break;
case '%':
/* /* %% is the same as % according to the SQL standard */
* Otherwise, scan for a text position at which we can /* Advance past all %'s */
* match the rest of the pattern. while ((plen > 0) && (*p == '%'))
*/ NextChar(p, plen);
for (; *text; text ++) /* Trailing percent matches everything. */
{ if (plen <= 0)
return LIKE_TRUE;
/* /*
* Optimization to prevent most recursion: don't * Otherwise, scan for a text position at which we can
* recurse unless first pattern char might match this * match the rest of the pattern.
* text char.
*/ */
if (*text == *p || *p == '\\' || *p == '_') while (tlen > 0)
{ {
int matched = DoMatch(text, p); /*
* Optimization to prevent most recursion: don't
* recurse unless first pattern char might match this
* text char.
*/
if ((*t == *p) || (*p == '\\') || (*p == '_')
|| ((e != NULL) && (*p == *e)))
{
int matched = MatchText(t, tlen, p, plen, e);
if (matched != LIKE_FALSE)
return matched; /* TRUE or ABORT */
}
if (matched != LIKE_FALSE) NextChar(t, tlen);
return matched; /* TRUE or ABORT */
} }
}
/* /*
* End of text with no match, so no point in trying later * End of text with no match, so no point in trying later
* places to start matching this pattern. * places to start matching this pattern.
*/ */
return LIKE_ABORT; return LIKE_ABORT;
}
} }
NextChar(t, tlen);
NextChar(p, plen);
} }
if (*text !='\0') if (tlen > 0)
return LIKE_FALSE; /* end of pattern, but not of text */ return LIKE_FALSE; /* end of pattern, but not of text */
/* End of input string. Do we have matching pattern remaining? */ /* End of input string. Do we have matching pattern remaining? */
while (*p == '%') /* allow multiple %'s at end of pattern */ while ((plen > 0) && (*p == '%')) /* allow multiple %'s at end of pattern */
p++; NextChar(p, plen);
if (*p == '\0') if (plen <= 0)
return LIKE_TRUE; return LIKE_TRUE;
/* /*
...@@ -223,16 +380,101 @@ DoMatch(pg_wchar * text, pg_wchar * p) ...@@ -223,16 +380,101 @@ DoMatch(pg_wchar * text, pg_wchar * p)
* start matching this pattern. * start matching this pattern.
*/ */
return LIKE_ABORT; return LIKE_ABORT;
} } /* MatchText() */
/* static int
** User-level routine. Returns TRUE or FALSE. MatchTextLower(pg_wchar * t, int tlen, pg_wchar * p, int plen, char *e)
*/
static bool
like(pg_wchar * text, pg_wchar * p)
{ {
/* Fast path for match-everything pattern */ /* Fast path for match-everything pattern
if (p[0] == '%' && p[1] == '\0') * Include weird case of escape character as a percent sign or underscore,
return true; * when presumably that wildcard character becomes a literal.
return DoMatch(text, p) == LIKE_TRUE; */
} if ((plen == 1) && (*p == '%')
&& ! ((e != NULL) && (*e == '%')))
return LIKE_TRUE;
while ((tlen > 0) && (plen > 0))
{
/* If an escape character was specified and we find it here in the pattern,
* then we'd better have an exact match for the next character.
*/
if ((e != NULL) && (tolower(*p) == tolower(*e)))
{
NextChar(p, plen);
if ((plen <= 0) || (tolower(*t) != tolower(*p)))
return LIKE_FALSE;
}
else
{
switch (*p)
{
case '\\':
/* Literal match with following character. */
NextChar(p, plen);
/* FALLTHROUGH */
default:
if (tolower(*t) != tolower(*p))
return LIKE_FALSE;
break;
case '_':
/* Match any single character. */
break;
case '%':
/* %% is the same as % according to the SQL standard */
/* Advance past all %'s */
while ((plen > 0) && (*p == '%'))
NextChar(p, plen);
/* Trailing percent matches everything. */
if (plen <= 0)
return LIKE_TRUE;
/*
* Otherwise, scan for a text position at which we can
* match the rest of the pattern.
*/
while (tlen > 0)
{
/*
* Optimization to prevent most recursion: don't
* recurse unless first pattern char might match this
* text char.
*/
if ((tolower(*t) == tolower(*p)) || (*p == '\\') || (*p == '_')
|| ((e != NULL) && (tolower(*p) == tolower(*e))))
{
int matched = MatchText(t, tlen, p, plen, e);
if (matched != LIKE_FALSE)
return matched; /* TRUE or ABORT */
}
NextChar(t, tlen);
}
/*
* End of text with no match, so no point in trying later
* places to start matching this pattern.
*/
return LIKE_ABORT;
}
}
NextChar(t, tlen);
NextChar(p, plen);
}
if (tlen > 0)
return LIKE_FALSE; /* end of pattern, but not of text */
/* End of input string. Do we have matching pattern remaining? */
while ((plen > 0) && (*p == '%')) /* allow multiple %'s at end of pattern */
NextChar(p, plen);
if (plen <= 0)
return LIKE_TRUE;
/*
* End of text with no match, so no point in trying later places to
* start matching this pattern.
*/
return LIKE_ABORT;
} /* MatchTextLower() */
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.39 2000/08/04 04:16:17 tgl Exp $ * $Id: catversion.h,v 1.40 2000/08/06 18:06:13 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200008031 #define CATALOG_VERSION_NO 200008061
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.160 2000/08/05 14:59:19 momjian Exp $ * $Id: pg_proc.h,v 1.161 2000/08/06 18:06:13 thomas Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2039,6 +2039,31 @@ DATA(insert OID = 1623 ( varchar PGUID 12 f t t t 1 f 1043 "20" 100 0 0 100 ...@@ -2039,6 +2039,31 @@ DATA(insert OID = 1623 ( varchar PGUID 12 f t t t 1 f 1043 "20" 100 0 0 100
DESCR("convert int8 to varchar"); DESCR("convert int8 to varchar");
DATA(insert OID = 1624 ( mul_d_interval PGUID 12 f t t t 2 f 1186 "701 1186" 100 0 0 100 mul_d_interval - )); DATA(insert OID = 1624 ( mul_d_interval PGUID 12 f t t t 2 f 1186 "701 1186" 100 0 0 100 mul_d_interval - ));
DATA(insert OID = 1625 ( like PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 1 0 namelike_escape - ));
DESCR("matches LIKE expression");
DATA(insert OID = 1626 ( notlike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 1 0 namenlike_escape - ));
DESCR("does not match LIKE expression");
DATA(insert OID = 1627 ( ilike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 1 0 inamelike_escape - ));
DESCR("matches case-insensitive LIKE expression");
DATA(insert OID = 1628 ( inotlike PGUID 12 f t t t 3 f 16 "19 25 25" 100 0 1 0 inamenlike_escape - ));
DESCR("does not match case-insensitive LIKE expression");
DATA(insert OID = 1629 ( like PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 1 0 textlike_escape - ));
DESCR("matches LIKE expression");
DATA(insert OID = 1630 ( notlike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 1 0 textnlike_escape - ));
DESCR("does not match LIKE expression");
DATA(insert OID = 1631 ( ilike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 1 0 itextlike_escape - ));
DESCR("matches case-insensitive LIKE expression");
DATA(insert OID = 1632 ( inotlike PGUID 12 f t t t 3 f 16 "25 25 25" 100 0 1 0 itextnlike_escape - ));
DESCR("does not match case-insensitive LIKE expression");
DATA(insert OID = 1633 ( ilike PGUID 12 f t t t 2 f 16 "25 25" 100 0 1 0 itextlike - ));
DESCR("matches case-insensitive LIKE expression");
DATA(insert OID = 1634 ( inotlike PGUID 12 f t t t 2 f 16 "25 25" 100 0 1 0 itextnlike - ));
DESCR("does not match case-insensitive LIKE expression");
DATA(insert OID = 1635 ( ilike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 inamelike - ));
DESCR("matches case-insensitive LIKE expression");
DATA(insert OID = 1636 ( inotlike PGUID 12 f t t t 2 f 16 "19 25" 100 0 0 100 inamenlike - ));
DESCR("does not match case-insensitive LIKE expression");
DATA(insert OID = 1689 ( update_pg_pwd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - )); DATA(insert OID = 1689 ( update_pg_pwd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - ));
DESCR("update pg_pwd file"); DESCR("update pg_pwd file");
...@@ -2291,9 +2316,9 @@ DESCR("greater-than"); ...@@ -2291,9 +2316,9 @@ DESCR("greater-than");
DATA(insert OID = 1721 ( numeric_ge PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_ge - )); DATA(insert OID = 1721 ( numeric_ge PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_ge - ));
DESCR("greater-than-or-equal"); DESCR("greater-than-or-equal");
DATA(insert OID = 1722 ( numeric_lt PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_lt - )); DATA(insert OID = 1722 ( numeric_lt PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_lt - ));
DESCR("lower-than"); DESCR("less-than");
DATA(insert OID = 1723 ( numeric_le PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_le - )); DATA(insert OID = 1723 ( numeric_le PGUID 12 f t t t 2 f 16 "1700 1700" 100 0 0 100 numeric_le - ));
DESCR("lower-than-or-equal"); DESCR("less-than-or-equal");
DATA(insert OID = 1724 ( numeric_add PGUID 12 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_add - )); DATA(insert OID = 1724 ( numeric_add PGUID 12 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_add - ));
DESCR("add"); DESCR("add");
DATA(insert OID = 1725 ( numeric_sub PGUID 12 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_sub - )); DATA(insert OID = 1725 ( numeric_sub PGUID 12 f t t t 2 f 1700 "1700 1700" 100 0 0 100 numeric_sub - ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.130 2000/08/03 23:07:51 tgl Exp $ * $Id: builtins.h,v 1.131 2000/08/06 18:06:44 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -431,8 +431,12 @@ extern Datum pgsql_version(PG_FUNCTION_ARGS); ...@@ -431,8 +431,12 @@ extern Datum pgsql_version(PG_FUNCTION_ARGS);
/* like.c */ /* like.c */
extern Datum namelike(PG_FUNCTION_ARGS); extern Datum namelike(PG_FUNCTION_ARGS);
extern Datum namenlike(PG_FUNCTION_ARGS); extern Datum namenlike(PG_FUNCTION_ARGS);
extern Datum namelike_escape(PG_FUNCTION_ARGS);
extern Datum namenlike_escape(PG_FUNCTION_ARGS);
extern Datum textlike(PG_FUNCTION_ARGS); extern Datum textlike(PG_FUNCTION_ARGS);
extern Datum textnlike(PG_FUNCTION_ARGS); extern Datum textnlike(PG_FUNCTION_ARGS);
extern Datum textlike_escape(PG_FUNCTION_ARGS);
extern Datum textnlike_escape(PG_FUNCTION_ARGS);
/* oracle_compat.c */ /* oracle_compat.c */
extern Datum lower(PG_FUNCTION_ARGS); extern Datum lower(PG_FUNCTION_ARGS);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment