--- /tmp/brz-diff-zt1ve7q4/old/rules/annotations/database_general.rules
+++ /home/om/repositories/local/fwd/5219a/rules/annotations/database_general.rules
@@ -144,12 +144,13 @@
 ** 063 DDF 20250424          Replaced file with artifact.
 ** 064 SP  20260802          Accept the word indexed field on either side of CONTAINS, normalizing
 **                           a reversed expression to field-first. 
-**         20260804          Reject a CONTAINS the 4GL will not carry, with its own error number: 
+**     SP  20260804          Reject a CONTAINS the 4GL will not carry, with its own error number: 
 **                           negated or non-word-indexed (3398), non-character operand (223), chained (247)
 **                           and, in a prepared query text only, USE-INDEX (3316), CAN-FIND (3541), a leading
 **                           FIRST/LAST (3322), and a subsequent LAST or a FIND (3318).
-**         20260814          Moved the 3322 refusal of a leading record phrase not opened by EACH to
+**     SP  20260814          Moved the 3322 refusal of a leading record phrase not opened by EACH to
 **                           DynamicQueryHelper, as the rule is not specific to a CONTAINS.
+**     OM  20260807          Additional expression validations for CONTAINS operator.
 -->
 
 <!--
@@ -1060,6 +1061,18 @@
          <action>ch1 = this.firstChild</action>
          <action>ch2 = this.getChildAt(1)</action>
 
+         <rule>ch1 == null or ch1.type != prog.field_char
+            <rule>isRuntimeQueryMode()
+               <action>
+                  compileError(223, "** Incompatible data types in expression or assignment", this)
+               </action>
+               <action on="false">
+                  printfln("WARNING: (%d:%d) Incompatible data types in expression or assignment. (223)",
+                           this.line, this.column)
+               </action>
+            </rule>
+         </rule>
+
          <!-- a chained CONTAINS is a syntax error, not a complaint about its operands, so the
               checks below are skipped for it -->
          <rule>ch1 != null and ch1.type == prog.kw_contains
@@ -1072,34 +1085,34 @@
             </rule>
          </rule>
 
+         <!-- a non-character operand is refused before the query opens; a LONGCHAR is not
+              character here, as a large object may not appear in a where clause at all -->
+         <rule>ch2 == null                  or
+               ch2.type == prog.unknown_val or
+               ((ch2.type &gt; prog.begin_vartypes and ch2.type &lt; prog.end_vartypes) and
+                ch2.type != prog.var_char) or
+               ((ch2.type &gt; prog.begin_fieldtypes and ch2.type &lt; prog.end_fieldtypes) and
+                ch2.type != prog.field_char)
+            <rule>isRuntimeQueryMode()
+               <action>
+                  compileError(223, "** Incompatible data types in expression or assignment", this)
+               </action>
+               <action on="false">
+                  printfln("WARNING: (%d:%d) Incompatible data types in expression or assignment. (223)",
+                           this.line, this.column)
+               </action>
+            </rule>
+         </rule>
+         
          <rule>ch1 == null or ch1.type != prog.kw_contains
             <variable name="badfld" type="java.lang.Boolean" />
             <variable name="recph"  type="com.goldencode.ast.Aast" />
             <variable name="lead"   type="com.goldencode.ast.Aast" />
             <variable name="inFind" type="java.lang.Boolean" />
-
-            <!-- a non-character operand is refused before the query opens; a LONGCHAR is not
-                 character here, as a large object may not appear in a where clause at all -->
-            <rule>ch2 != null and
-                  (ch2.type == prog.unknown_val or
-                   ((ch2.type &gt; prog.begin_vartypes and ch2.type &lt; prog.end_vartypes) and
-                    ch2.type != prog.var_char))
-               <rule>isRuntimeQueryMode()
-                  <action>
-                     compileError(223, "** Incompatible data types in expression or assignment",
-                                  this)
-                  </action>
-                  <action on="false">
-                     printfln(
-                        "WARNING: (%d:%d) Incompatible data types in expression or assignment. (223)",
-                        this.line, this.column)
-                  </action>
-               </rule>
-            </rule>
-
+            
             <!-- a negated CONTAINS and a non-word-indexed one share error 3398, so they are
                  decided together and reported once -->
-            <action>badfld = ch1 == null or !ch1.isAnnotation("word-indexed")</action>
+            <action>badfld = (ch1 == null) or !ch1.isAnnotation("word-indexed")</action>
             <rule>badfld and ch2 != null and ch2.isAnnotation("word-indexed")
                <action>badfld = false</action>
                <action>copy.getChildAt(1).move(null, 0)</action>
@@ -1111,8 +1124,7 @@
             <rule>badfld
                <rule>isRuntimeQueryMode()
                   <action>
-                     compileError(3398, "CONTAINS allowed only for word indexed field references",
-                                  this)
+                     compileError(3398, "CONTAINS allowed only for word indexed field references", this)
                   </action>
                   <action on="false">
                      printfln(

