diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e8abfe039f091ce53a3cd9e1759d86efd2d0d8a6..84efc2875eee44c7dd043fb06a6285839dcdb425 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.449 2004/03/17 20:48:42 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.450 2004/04/05 03:07:26 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -194,7 +194,7 @@ static void doNegateFloat(Value *v);
 				database_name access_method_clause access_method attr_name
 				index_name name function_name file_name
 
-%type <list>	func_name handler_name qual_Op qual_all_Op
+%type <list>	func_name handler_name qual_Op qual_all_Op subquery_Op
 				opt_class opt_validator
 
 %type <range>	qualified_name OptConstrFromTable
@@ -5692,7 +5692,7 @@ r_expr:  row IN_P select_with_parens
 					/* Stick a NOT on top */
 					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n);
 				}
-			| row qual_all_Op sub_type select_with_parens
+			| row subquery_Op sub_type select_with_parens
 			%prec Op
 				{
 					SubLink *n = makeNode(SubLink);
@@ -5702,7 +5702,7 @@ r_expr:  row IN_P select_with_parens
 					n->subselect = $4;
 					$$ = (Node *)n;
 				}
-			| row qual_all_Op select_with_parens
+			| row subquery_Op select_with_parens
 			%prec Op
 				{
 					SubLink *n = makeNode(SubLink);
@@ -5712,7 +5712,7 @@ r_expr:  row IN_P select_with_parens
 					n->subselect = $3;
 					$$ = (Node *)n;
 				}
-			| row qual_all_Op row
+			| row subquery_Op row
 			%prec Op
 				{
 					$$ = makeRowExpr($2, $1, $3);
@@ -5807,6 +5807,23 @@ qual_all_Op:
 			| OPERATOR '(' any_operator ')'			{ $$ = $3; }
 		;
 
+subquery_Op:
+			all_Op { $$ = makeList1(makeString($1)); }
+			| OPERATOR '(' any_operator ')'			{ $$ = $3; }
+			| LIKE { $$ = makeList1(makeString("~~")); }
+			| NOT LIKE { $$ = makeList1(makeString("!~~")); }
+			| ILIKE { $$ = makeList1(makeString("~~*")); }
+			| NOT ILIKE { $$ = makeList1(makeString("!~~*")); }
+/* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
+ * the regular expression is preprocessed by a function (similar_escape),
+ * and the ~ operator for posix regular expressions is used. 
+ *        x SIMILAR TO y     ->    x ~ similar_escape(y)
+ * this transformation is made on the fly by the parser upwards.
+ * however the SubLink structure which handles any/some/all stuff
+ * is not ready for such a thing.
+ */
+			;
+
 /*
  * General expressions
  * This is the heart of the expression syntax.
@@ -6132,7 +6149,7 @@ a_expr:		c_expr									{ $$ = $1; }
 						$$ = n;
 					}
 				}
-			| a_expr qual_all_Op sub_type select_with_parens %prec Op
+			| a_expr subquery_Op sub_type select_with_parens %prec Op
 				{
 					SubLink *n = makeNode(SubLink);
 					n->subLinkType = $3;
@@ -6141,7 +6158,7 @@ a_expr:		c_expr									{ $$ = $1; }
 					n->subselect = $4;
 					$$ = (Node *)n;
 				}
-			| a_expr qual_all_Op sub_type '(' a_expr ')' %prec Op
+			| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
 				{
 					if ($3 == ANY_SUBLINK)
 						$$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5);
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 6f3c07cfb3fbf46c39247a1980ede0cde6417d84..6e82a7d0a6c70d876712a6f9c979da00a81a21e0 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -377,3 +377,52 @@ select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
 
 -- note: if above select doesn't produce the expected tuple order,
 -- then you didn't get an indexscan plan, and something is busted.
+-- test [not] (like|ilike) (any|all) (...)
+select 'foo' like any (array['%a', '%o']); -- t
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'foo' like any (array['%a', '%b']); -- f
+ ?column? 
+----------
+ f
+(1 row)
+
+select 'foo' like all (array['f%', '%o']); -- t
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'foo' like all (array['f%', '%b']); -- f
+ ?column? 
+----------
+ f
+(1 row)
+
+select 'foo' not like any (array['%a', '%b']); -- t
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'foo' not like all (array['%a', '%o']); -- f
+ ?column? 
+----------
+ f
+(1 row)
+
+select 'foo' ilike any (array['%A', '%O']); -- t
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'foo' ilike all (array['F%', '%O']); -- t
+ ?column? 
+----------
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 3bc800cef21c99b3a8cff41578202522d4630c46..629ca15fb1c45221f7e5f05f4c5ecdd3743febed 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -183,3 +183,13 @@ set enable_seqscan to off;
 select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
 -- note: if above select doesn't produce the expected tuple order,
 -- then you didn't get an indexscan plan, and something is busted.
+
+-- test [not] (like|ilike) (any|all) (...)
+select 'foo' like any (array['%a', '%o']); -- t
+select 'foo' like any (array['%a', '%b']); -- f
+select 'foo' like all (array['f%', '%o']); -- t
+select 'foo' like all (array['f%', '%b']); -- f
+select 'foo' not like any (array['%a', '%b']); -- t
+select 'foo' not like all (array['%a', '%o']); -- f
+select 'foo' ilike any (array['%A', '%O']); -- t
+select 'foo' ilike all (array['F%', '%O']); -- t