Search queries test values
Queries that a search box reads as wildcards, query syntax or a broken address instead of the text the user typed. 17 values, each with what it breaks and what a correct application does instead.
Type them one at a time with AltShiftN
in the palette, or take them all into a script with nkb emit search-queries.
Search for 100%
search-queries/percent
100%
100%
- 4 graphemes
- 4 code points
- 4 bytes
- 4 UTF-16 units
- What it breaks
- In SQL LIKE a percent sign matches anything, and a parameterised query does not escape it, so PostgreSQL, MySQL and SQLite return every row that merely contains 100, such as 1000 items.
- What a correct application does
- Only results that contain the text 100%.
Search with an underscore
search-queries/underscore
a_b
a_b
- 3 graphemes
- 3 code points
- 3 bytes
- 3 UTF-16 units
- What it breaks
- In LIKE an underscore matches any single character, so a_b also finds a-b, axb and the a?b of a pasted link, and code that escapes the percent sign often forgets this one.
- What a correct application does
- Only results that contain a_b.
A single asterisk
search-queries/asterisk
*
*
- 1 grapheme
- 1 code point
- 1 byte
- 1 UTF-16 unit
- What it breaks
- A wildcard on its own: Elasticsearch query_string returns the whole index, MySQL full-text search and SQLite FTS5 refuse it with a syntax error, and a regular expression built from the query fails with nothing to repeat.
- What a correct application does
- Results that contain an asterisk, an empty result, or a message, never everything and never an error page.
Quote that is never closed
search-queries/unbalanced-quote
"annualreport
"annual report
- 14 graphemes
- 14 code points
- 14 bytes
- 14 UTF-16 units
- What it breaks
- Elasticsearch query_string, SQLite FTS5 and to_tsquery in PostgreSQL read the quote as the start of a phrase that never ends and stop with a parse error, which an application that passes it on shows as an error page.
- What a correct application does
- Results for the two words, with the quote ignored or searched as text.
Bracket that is never closed
search-queries/unbalanced-paren
(draft
(draft
- 6 graphemes
- 6 code points
- 6 bytes
- 6 UTF-16 units
- What it breaks
- A bracket opens a group that never closes: Elasticsearch query_string, SQLite FTS5, to_tsquery in PostgreSQL, MySQL boolean full-text search and a regular expression built from the query in Python or JavaScript all stop with a syntax error.
- What a correct application does
- Results for draft, with the bracket ignored or searched as text.
Word followed by a backslash
search-queries/backslash-end
draft\
draft\\
- 6 graphemes
- 6 code points
- 6 bytes
- 6 UTF-16 units
- What it breaks
- A backslash at the end escapes nothing, so Elasticsearch query_string, SQLite FTS5, to_tsquery in PostgreSQL and a regular expression built from the query in Python or JavaScript stop with a syntax error.
- What a correct application does
- Results for draft followed by a backslash, an empty result or a message, never an error page.
Search for C++
search-queries/c-plus-plus
C++
C++
- 3 graphemes
- 3 code points
- 3 bytes
- 3 UTF-16 units
- What it breaks
- Tokenisers drop the plus signs, so Elasticsearch and PostgreSQL full-text search return every result with the letter C, SQLite FTS5 and MySQL boolean mode stop with a syntax error, and in a URL built by hand each plus arrives as a space.
- What a correct application does
- Results about C++ first, not every result with the letter C.
Search for C#
search-queries/c-sharp
C#
C#
- 2 graphemes
- 2 code points
- 2 bytes
- 2 UTF-16 units
- What it breaks
- Added to a URL by hand without encoding, the hash sign starts the fragment and the server searches for C. Elasticsearch and PostgreSQL full-text search drop the hash sign too, and MySQL full-text search ignores a word that short.
- What a correct application does
- Results about C#, with the hash sign reaching the server encoded as %23.
Phrase made only of stop words
search-queries/stop-words
tobeornottobe
to be or not to be
- 18 graphemes
- 18 code points
- 18 bytes
- 18 UTF-16 units
- What it breaks
- Every word is on the English stop list of PostgreSQL full-text search, so the query becomes empty and the user finds nothing for a famous phrase.
- What a correct application does
- Results that contain the phrase, or a message that the query was too common.
Words joined by AND
search-queries/boolean-words
saltANDpepper
salt AND pepper
- 15 graphemes
- 15 code points
- 15 bytes
- 15 UTF-16 units
- What it breaks
- SQLite FTS5 and Lucene query syntax read upper-case AND as an operator, and full-text search matches the words anywhere, so a record called pepper with sea salt comes up for the phrase the user typed.
- What a correct application does
- The same results as for salt and pepper, or the phrase searched as typed.
Step 1: save a record named Lodz with Polish letters
search-queries/diacritics-storedpair 1 of 2 Polish spelling against the same word without accents
Łódź
Łódź
- 4 graphemes
- 4 code points
- 7 bytes
- 4 UTF-16 units
- What it breaks
- Step 1 of the accent test: save a record with this name, the Polish spelling of the city, before searching for it without accents.
- What a correct application does
- Saved as typed.
Step 2: search for lodz without accents
search-queries/diacritics-searchedpair 2 of 2 Polish spelling against the same word without accents
lodz
lodz
- 4 graphemes
- 4 code points
- 4 bytes
- 4 UTF-16 units
- What it breaks
- Step 2: search for the record from step 1 typed without Polish letters, as most users type on a keyboard without them.
- What a correct application does
- The record from step 1 is found.
Three spaces
search-queries/spaces-only
3 ×
- starts with a space
- ends with a space
- 3 graphemes
- 3 code points
- 3 bytes
- 3 UTF-16 units
- What it breaks
- Trimmed to an empty query, which some searches answer with every row and others with an error: SQLite FTS5 refuses it, and a URL built by hand loses trailing spaces, so the server receives an empty query.
- What a correct application does
- An empty result or a message, the same as for an empty search box.
Pasted link
search-queries/url-query
https://example.com/a?b=1
https://example.com/a?b=1
- 25 graphemes
- 25 code points
- 25 bytes
- 25 UTF-16 units
- What it breaks
- Elasticsearch query_string reads the colon as a field name and the slash as the start of a regular expression and refuses the link, SQLite FTS5 answers no such column, and match queries return every record with example or com.
- What a correct application does
- Records that contain the link.
E-mail address
search-queries/email-query
first.last@example.com
first.last@example.com
- 22 graphemes
- 22 code points
- 22 bytes
- 22 UTF-16 units
- What it breaks
- Elasticsearch and MySQL full-text search split the address at the at sign and the dots and return every record with example or com, MySQL boolean mode refuses the at sign, and SQLite FTS5 refuses the dot.
- What a correct application does
- The record with this address first.
Invoice number with slashes
search-queries/invoice-number
FV/2027/11/001
FV/2027/11/001
- 14 graphemes
- 14 code points
- 14 bytes
- 14 UTF-16 units
- What it breaks
- Elasticsearch query_string reads a slash as the start of a regular expression and refuses the number, and full-text search in Elasticsearch and MySQL splits it at the slashes and returns every invoice and every other record from 2027.
- What a correct application does
- The invoice with this number first.
16500 characters
search-queries/long-query
16,500 × a
- 16,500 graphemes
- 16,500 code points
- 16,500 bytes
- 16,500 UTF-16 units
- What it breaks
- Sent as a GET parameter, the query is longer than web servers accept by default: IIS answers 404 above 2048 bytes, nginx, Apache and Kestrel 414 above about 8 KB, and Node 431 above 16 KB, an error page instead of results or a message.
- What a correct application does
- Results, or a message that the query is too long.
Pairs
Each pair is two of the values above, worth typing side by side: into two fields, or into one field twice. AltShiftN types them in turn, and the palette says which half of a pair comes next.
Polish spelling against the same word without accents
search-queries/diacriticspair 1 of 2 Step 1: save a record named Lodz with Polish letters
Łódź- 4 graphemes
- 4 code points
- 7 bytes
- 4 UTF-16 units
pair 2 of 2 Step 2: search for lodz without accents
lodz- 4 graphemes
- 4 code points
- 4 bytes
- 4 UTF-16 units
- What it breaks
- Step 3: a search that strips accents after NFD decomposition still misses the record, because the Polish l with stroke has no decomposition. The unaccent extension of PostgreSQL and the accent-insensitive default collation of MySQL find it, while plain LIKE, SQLite, Elasticsearch with its default analyser and JavaScript do not.
- What a correct application does
- The search for lodz finds the record saved with Polish letters.