{"record":{"id":"0b3f3b6c7b7c5a1f","repo":"hibernate/hibernate-orm","slug":"unquoted-count-of-quotes-is-invalid","errorCode":null,"errorMessage":"Unquoted count of quotes is invalid","messagePattern":"Unquoted count of quotes is invalid","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java","lineNumber":536,"sourceCode":"\t\t\treturn 0;\n\t\t}\n\t\ttext = text.trim();\n\t\tif ( text.isEmpty() ) {\n\t\t\treturn 0;\n\t\t}\n\t\tint count = 0;\n\t\tfor ( int i = 0, max = text.length(); i < max; i++ ) {\n\t\t\tfinal char check = text.charAt( i );\n\t\t\tif ( check == match ) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tpublic static int countUnquoted(String string, char character) {\n\t\tif ( '\\'' == character ) {\n\t\t\tthrow new IllegalArgumentException( \"Unquoted count of quotes is invalid\" );\n\t\t}\n\t\tif ( string == null ) {\n\t\t\treturn 0;\n\t\t}\n\t\t// Impl note: takes advantage of the fact that an escaped single quote\n\t\t// embedded within a quote-block can really be handled as two separate\n\t\t// quote-blocks for the purposes of this method...\n\t\tint count = 0;\n\t\tfinal int stringLength = string.length();\n\t\tboolean inQuote = false;\n\t\tfor ( int indx = 0; indx < stringLength; indx++ ) {\n\t\t\tchar c = string.charAt( indx );\n\t\t\tif ( inQuote ) {\n\t\t\t\tif ( '\\'' == c ) {\n\t\t\t\t\tinQuote = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( '\\'' == c ) {","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java#L518-L554","documentation":"StringHelper.countUnquoted(string, character) counts occurrences of a character outside single-quoted regions, so counting the single-quote character itself is meaningless — every quote is both the delimiter and the candidate match. The method therefore rejects the quote character up front with IllegalArgumentException. This is an invariant guard, not a runtime condition you can hit with data.","triggerScenarios":"Calling StringHelper.countUnquoted(text, '\\'') — the check fires immediately regardless of the string argument, before any scanning starts.","commonSituations":"Generic character-counting utilities that iterate over candidate characters including quotes; copy-paste use of the helper while inspecting SQL fragments for delimiters; code written against count() and adapted to countUnquoted() without dropping the quote case.","solutions":["If you need the total number of single quotes, use StringHelper.count(string, '\\'') instead.","If you need quotes outside quote-blocks, note that each quote flips in/out of a block — the concept is ill-defined, so rethink the parsing (e.g., a proper tokenizer).","If iterating over characters, skip '\\'' explicitly when delegating to countUnquoted."],"exampleFix":"// before\nint n = StringHelper.countUnquoted(sql, '\\''); // IllegalArgumentException\n\n// after\nint totalQuotes = StringHelper.count(sql, '\\'');","handlingStrategy":"validation","validationCode":"static int safeCountUnquoted(String text, char c) {\n    if (c == '\\'') {\n        return StringHelper.count(text, '\\''); // quote char not supported by countUnquoted\n    }\n    return StringHelper.countUnquoted(text, c);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Read the helper's contract: the counted character must differ from the quote delimiter.","When counting delimiters in SQL fragments, pick the counting function per character explicitly."],"tags":["hibernate","string-utils","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}