4 The qstore server (open-ils.qstore) executes database queries that have
5 been previously defined, in an abstract form, within the database
6 itself. Such queries may be used for periodic reporting, ad hoc
7 investigations, or automated updates.
9 In some cases a query may be qualified by values to be supplied at
10 execution time, called bind variables. For example, a query may be
11 limited to a particular org unit, or a short list of user ids.
13 Before executing a query, the qstore client must open an application
14 session with the qstore server by sending it a CONNECT message. Then it
15 must perform a series of steps to set up the query, execute it, and get
16 the results. Finally, the client may close the query explicitly with an
17 additional method call. Alternatively it may simply close the
18 application session by sending a DISCONNECT message to the server.
20 Here is a brief summary of the available methods. Each will be
21 discussed in greater detail in a later section:
23 . open-ils.qstore.prepare – load the query
24 . open-ils.qstore.sql – return the query as SQL
25 . open-ils.qstore.param_list – return a list of bind variables
26 . open-ils.qstore.bind_param – assign values to one or more bind
28 . open-ils.qstore.execute – execute the query and return the results
29 . open-ils.qstore.execute.atomic – an atomic version of the execute
31 . open-ils.qstore.columns – return a list of column names for the
33 . open-ils.qstore.finish – close a query, freeing any associated
35 . open-ils.qstore.messages – return any error message for a specified
40 Summary: Load a specified query. Return a list of bind variables, and
41 a token by which the query may be referenced in future method calls.
43 Parameter: The id of a row in the query.stored_query table, identifying
46 Returns: A JSON object with two members:
48 . “token”: a text string to be used as a token for identifying the
49 query in future method calls. This string is designed to be unique, but
50 otherwise has no very useful meaning.
51 . “bind_variables”: a (possibly empty) JSON object defining any bind
52 variables required by the query. See the discussion of the bind_param
55 A client may juggle multiple queries in the same application session,
56 using the corresponding tokens to identify the query to which each
61 Summary: Return the query as an SQL string.
63 Parameter: The token returned previously by the prepare method for the
66 Returns: A string containing the generated SQL corresponding to the
67 stored query. It will incorporate the specified values of any bind
68 variables. If no value has been assigned to a given bind variable, and
69 there is no default value for it, then the generated SQL will include
70 the name of the bind variable wherever it appears, preceded by a colon
71 to distinguish it from a column name. The user may review such a query
72 but cannot execute it.
76 Summary: Returns information about the bind variables required by the
79 Parameter: The token returned previously by the prepare method for the
82 Returns: A JSON object keyed on the bind variable name. The data
83 associated with each name is another JSON object, with the following
86 . “label”: the contents of query.bind_variable.label for this
87 variable. This is the identifier usually shown to the user for this
89 . “type”: the contents of query.bind_variable.type for this variable.
90 It is one of “string”, “number”, “string_list”, or “number_list”.
91 . “description”: the contents of query.bind_variable.description for
93 . “default_value”: the value that will be assigned to the variable if
94 the user doesn't override it.
95 . “actual_value”: the value assigned by the user, overriding any
98 Depending on the type, the default or actual value of a bind variable
99 may be a string, a number, a JSON array of strings, or a JSON array of
102 If a given variable has no default value, then there will be no entry
103 for “default_value”. On the other hand if the default value is a null,
104 then there will be an entry for “default_value” whose associated data is
105 a JSON null. Likewise for “actual_value”.
107 The bind_param method
108 ---------------------
109 Summary: Assign a value to one or more bind variables.
111 Parameter: This is the only qstore method that requires two parameters:
113 . The token returned previously by the prepare method for the same
115 . A (possibly empty) JSON object keyed on bind variable name. The
116 value associated with each bind variable name is the value to be
117 assigned to the corresponding bind variable, overriding any default, and
118 replacing any value previously assigned.
122 Summary: Execute the specified query, and return the results.
124 Parameter: The token returned previously by the prepare method for the
127 Returns: Zero or more responses, each containing one row returned by the
128 query. Each row is represented by a JSON array of values.
130 The execute.atomic method
131 -------------------------
132 Summary: Execute the specified query, and return the results.
134 Parameter: The token returned previously by the prepare method for the
137 Returns: A JSON array containing zero or more entries. Each entry
138 represents a row as a JSON array of values.
142 Summary: Return the column names assigned by PostgreSQL to the result
145 Parameter: The token returned previously by the prepare method for the
148 Returns: An array of strings, each string being a column name.
152 Summary: Close a query, freeing any resources associated with it, and
153 rendering the token invalid for future method calls.
155 Parameter: The token returned previously by the prepare method for the
158 Closing the application session will finish any unfinished queries for
163 Summary: Return any error messages associated with a query.
165 Parameter: The token returned previously by the prepare method for the
168 Returns: A JSON array of strings, each string being an error message
169 issued in connection with the specified query. The messages appear in
170 the order in which they were issued. Typically the first message
171 describes the error as it was first encountered, and subsequent messages
172 describe the context in which the error occurred.
174 The messages returned include all those issued for the specified query,
175 including any issued for previous method calls. Since currently there
176 is no method for purging error messages, they just accumulate.
178 In many cases (but not all), qstore writes similar messages to its log.
179 The messages method is based on the notion that most users shouldn't
180 have to examine log files. They may however need help in interpreting
185 The following srfsh session illustrates these methods. After opening an
186 application session, we prepare query 12:
189 srfsh# open open-ils.qstore
191 Service open-ils.qstore opened
193 srfsh# request open-ils.qstore open-ils.qstore.prepare 12
196 "token":"1_1279135310_6487",
201 "description":"org unit"
207 The server concocts a unique token, "1_1279135310_6487”, that we will
208 use henceforth to identify this query. We could also prepare an
209 unrelated query, or even the same query more than once, and qstore would
210 assign each of them a different token and keep them all straight. For
211 this example, though, we'll stick to the one query.
213 This query has one bind variable named “ou”, whose value needs to be
214 numeric. The label, “lib”, is a short name for handy reference
215 (although in this case it's actually longer than the name used
216 internally). The description tells us that it identifies an org unit.
217 In a real example the description probably should be more verbose, so
218 that user could see it in a tool tip (for example) and figure out what
221 In this case there is no default value, i.e. there is no entry for
222 “default_value”. That means we can't run the query yet – but we can
223 still look at the SQL for it:
226 srfsh# request open-ils.qstore open-ils.qstore.sql "1_1279135310_6487"
228 Received Data: "SELECT\n \"aou\".id,\n \"aou\".name,\n
231 \"aou\".opac_visible,\n \"aou\".parent_ou \nFROM\n actor.org_unit AS
232 \"aou\" \nWHERE\n \"aou\".id = :ou;\n"
235 When we call the sql method, we pass it the token that the prepare
236 method assigned earlier. The server returns the generated SQL, trying
237 to make it readable by inserting newlines and indentation. In srfsh,
238 though, the output is pretty ugly because all the newlines and quotation
239 marks are escaped within a JSON string. In this document, at least,
240 it's line-wrapped so that it fits on the page. In a proper GUI it
241 should look much nicer.
243 At the end of the SQL, the query refers to the bind variablee as “:ou”,
244 the variable preceded by a colon. The colon indicates that “ou” is a
245 variable name rather than a column name. It also makes the SQL invalid
246 until we replace the variable with a real value. Let's do that now, and
247 then look at the SQL again:
250 srfsh# request open-ils.qstore open-ils.qstore.bind_param \
251 "1_1279135310_6487" {"ou":3}
253 srfsh# request open-ils.qstore open-ils.qstore.sql "1_1279135310_6487"
255 Received Data: "SELECT\n \"aou\".id,\n \"aou\".name,\n
257 \"aou\".opac_visible,\n \"aou\".parent_ou \nFROM\n actor.org_unit
258 AS \"aou\" \nWHERE\n \"aou\".id = 3;\n"
261 When we call the bind_param method we pass not only the token but also a
262 JSON object assigning a value to one or more bind variables – just one
263 in this case. Now the generated SQL looks normal.
265 We can also verify the substitution by calling the param_list method:
268 srfsh# request open-ils.qstore open-ils.qstore.param_list \
275 "description":"org unit",
281 Now we see an “actual_value” of 3. The SQL is ready to go.
284 srfsh# request open-ils.qstore open-ils.qstore.execute
296 This query returns only one row, so we get only one response. If there
297 were multiple rows, srfsh would display multiple lines of “Received
298 Data.” The one response is a JSON array of column values.
300 Here's the atomic version of the same method call:
303 srfsh# request open-ils.qstore open-ils.qstore.execute.atomic \
317 The difference isn't obvious because there's only one row, but notice
318 the an extra layer of square brackets. This result is an array of
319 arrays of column values. If there were multiple rows, they'd all be in
322 This response does not identify the columns. For that we must make
326 srfsh# request open-ils.qstore open-ils.qstore.columns
338 The result is a JSON array of column names. These are the same names
339 that you would get if you ran the query in psql. They may not be unique
340 or even helpful. Ideally the query should assign good column aliases,
341 but if it doesn't, you have to take what you can get.
343 Now let's make a mistake, just so that we can see an error message.
344 We're going to assign a value to a bind variable that doesn't exist,
345 and then ask for any error messages:
348 srfsh# request open-ils.qstore open-ils.qstore.bind_param
349 "1_1279135310_6487" {"goober":3}
352 Name: osrfMethodException
353 Status: Unable to apply values to bind variables
356 Name: osrfMethodException
357 Status: An unknown server error occurred
360 srfsh# request open-ils.qstore open-ils.qstore.messages
364 "Can't assign value to bind variable \"goober\": no such variable"
368 The result is a JSON array of error messages as strings. In this case
369 there's only one message. In other cases there may be a series of
370 messages, the first one describing the error at the lowest level, and
371 the rest providing additional context.
373 Now that we're done with this query, we can shut it down:
376 srfsh# request open-ils.qstore open-ils.qstore.finish
379 Received no data from server
381 srfsh# close open-ils.qstore
383 Service "open-ils.qstore" closed
388 The finish method closes the query and frees associated memory. In this
389 case we could have skipped it, because we immediately close the session
390 anyway, thereby closing any outstanding queries.