@@ -130,8 +130,9 @@ else if (this.partTree.isDelete()) {
130130 cypher .append (" RETURN n" );
131131 }
132132
133- // Add ORDER BY clause
134- if (sort .isSorted () && !this .partTree .isDelete ()) {
133+ // Add ORDER BY clause (only for regular SELECT queries, not for count/exists/delete)
134+ if (sort .isSorted () && !this .partTree .isDelete () && !this .partTree .isCountProjection ()
135+ && !this .partTree .isExistsProjection ()) {
135136 cypher .append (" ORDER BY " );
136137 boolean first = true ;
137138 for (Sort .Order order : sort ) {
@@ -168,6 +169,13 @@ private void appendCondition(StringBuilder cypher, Part part, Map<String, Object
168169
169170 String property = part .getProperty ().toDotPath ();
170171 String paramName = "param" + parameterIndex .getAndIncrement ();
172+ int currentParamIndex = parameterIndex .get () - 1 ;
173+
174+ // Validate parameter index bounds
175+ if (currentParamIndex >= parameters .length ) {
176+ throw new IllegalArgumentException ("Parameter index " + currentParamIndex
177+ + " out of bounds for parameters array of length " + parameters .length );
178+ }
171179
172180 switch (part .getType ()) {
173181 case SIMPLE_PROPERTY :
@@ -196,26 +204,36 @@ private void appendCondition(StringBuilder cypher, Part part, Map<String, Object
196204 break ;
197205 case LIKE :
198206 cypher .append ("n." ).append (property ).append (" =~ $" ).append (paramName );
199- // Convert SQL LIKE to regex pattern
207+ // Convert SQL LIKE to regex pattern with proper escaping
200208 String likeValue = String .valueOf (parameters [parameterIndex .get () - 1 ]);
201- String regexPattern = "(?i)" + likeValue .replace ("%" , ".*" ).replace ("_" , "." );
209+ // Split by wildcards, escape each part, then reassemble
210+ String regexPattern = likeValue .replace ("%" , "\u0000 " ).replace ("_" , "\u0001 " );
211+ regexPattern = java .util .regex .Pattern .quote (regexPattern );
212+ regexPattern = regexPattern .replace ("\\ Q\u0000 \\ E" , ".*" ).replace ("\\ Q\u0001 \\ E" , "." );
213+ regexPattern = "(?i)" + regexPattern ;
202214 queryParameters .put (paramName , regexPattern );
203215 break ;
204216 case STARTING_WITH :
205217 cypher .append ("n." ).append (property ).append (" =~ $" ).append (paramName );
206- queryParameters .put (paramName , "(?i)" + parameters [parameterIndex .get () - 1 ] + ".*" );
218+ String startValue = String .valueOf (parameters [parameterIndex .get () - 1 ]);
219+ queryParameters .put (paramName , "(?i)" + java .util .regex .Pattern .quote (startValue ) + ".*" );
207220 break ;
208221 case ENDING_WITH :
209222 cypher .append ("n." ).append (property ).append (" =~ $" ).append (paramName );
210- queryParameters .put (paramName , "(?i).*" + parameters [parameterIndex .get () - 1 ]);
223+ String endValue = String .valueOf (parameters [parameterIndex .get () - 1 ]);
224+ queryParameters .put (paramName , "(?i).*" + java .util .regex .Pattern .quote (endValue ));
211225 break ;
212226 case CONTAINING :
213227 cypher .append ("n." ).append (property ).append (" =~ $" ).append (paramName );
214- queryParameters .put (paramName , "(?i).*" + parameters [parameterIndex .get () - 1 ] + ".*" );
228+ String containValue = String .valueOf (parameters [parameterIndex .get () - 1 ]);
229+ queryParameters .put (paramName ,
230+ "(?i).*" + java .util .regex .Pattern .quote (containValue ) + ".*" );
215231 break ;
216232 case NOT_CONTAINING :
217233 cypher .append ("NOT n." ).append (property ).append (" =~ $" ).append (paramName );
218- queryParameters .put (paramName , "(?i).*" + parameters [parameterIndex .get () - 1 ] + ".*" );
234+ String notContainValue = String .valueOf (parameters [parameterIndex .get () - 1 ]);
235+ queryParameters .put (paramName ,
236+ "(?i).*" + java .util .regex .Pattern .quote (notContainValue ) + ".*" );
219237 break ;
220238 case IS_NULL :
221239 cypher .append ("n." ).append (property ).append (" IS NULL" );
0 commit comments