It is one of the most frequently utilized classes within ServiceNow. Whenever we encounter minor data needs in server-side scripts, GlideRecord is consistently relied upon. This reliance is such that we often trust the data returned by a GlideRecord query without question, as if to say, “It’s GlideRecord; it won’t let us down.”
In fact, the opposite is true. GlideRecord depends heavily on our scripting logic and lacks a built-in failsafe mechanism by default. Uncertain about what I mean? Not to worry, I’ll clarify everything in the following examples.
General syntax
var grTable = new GlideRecord('table');
grTable.addQuery('field1', value1);
grTable.addQuery('field2', value2);
.
.
.
.
/* All addQuery lines can be replaced with
one addEncodedQuery() if we have it handy */
grTable.query();
while (grTable.next()) {
/* Do something */
}
The problem
Code snippet 1
Try running the below snippet in a background script on a PDI.
var grInc = new GlideRecord('incident');
/* Replace INC number with one that exists
on the PDI */
grInc.addQuery('number', 'INC0000003');
grInc.query();
while(grInc.next()) {
gs.info(grInc.getValue('number'));
}
What was the output? It should look similar to the following.
Code snippet 2
Now open a new browser tab with background script and try running the below snippet.
var grInc = new GlideRecord('incident');
/* Replace INC number with one that exists
on the PDI */
grInc.addQuery('nnumber', 'INC0000003');
grInc.query();
while(grInc.next()) {
gs.info(grInc.getValue('number'));
}
What was the output? How long did it take to finish? The output should begin with something like this.
Does this imply our script failed to execute? Far from it! Just continue scrolling down in the output section, and as we scroll, appears a list showing the numbers of all incidents currently in the system.
What exactly went wrong? It appears that our script executed without error, but GlideRecord failed to retrieve the expected data. Despite detecting an invalid query, it proceeded to return the entire table’s data as if no query had been specified initially.
In the second code snippet, there was a typo where we used ‘nnumber’ instead of ‘number’. And yes, the issue persists even if we use addEncodedQuery() instead of addQuery(). Feel free to give it a try; we’ll wait.
The fix
Because we cannot modify the core GlideRecord functions, we’ll need to adjust our logic to handle invalid queries and stop the script from running.
Code snippet 3
Try running the below snippet.
var grInc = new GlideRecord('incident');
/* Replace INC number with one that exists
on the PDI */
grInc.addQuery('nnumber', 'INC0000003');
/* Inserting a query validation check before
executing the query */
var query = grInc.getEncodedQuery();
if (grInc.isValidEncodedQuery(query)) {
grInc.query();
while (grInc.next()) {
gs.info(grInc.getValue('number'));
}
} else {
gs.info('Invalid query detected.');
}
The output should resemble what’s shown below.
What happened here? We used a function in the GlideRecord class that isn’t commonly used – isValidEncodedQuery(). Including these few lines of validation can prevent data mishaps in production. Sometimes, queries aren’t directly written by us but are returned from other function calls. Even in such cases, isValidEncodedQuery() can ensure data integrity and act as a safeguard.
- Reference – isValidEncodedQuery
Next steps
Aim to instil a habit of using isValidEncodedQuery() in our GlideRecord implementations and ensure that our fellow developers adopt this practice as well.
Additionally, we can implement a global solution by establishing a system property ‘glide.invalid_query.returns_no_rows’ and setting its value to ‘true’. This configuration would ensure that no records are returned if the GlideRecord query is invalid, and it applies across the entire instance. Thank you, Ahmed for this information.