Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/conditions.lisp

KindCoveredAll%
expression102451 22.6
branch16 16.7
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.implementation; -*-
2
 
3
 (in-package :org.datagraph.spocq.implementation)
4
 
5
 (:documentation "conditions"
6
   "The conditions reflect two situations: either an error occurs because some aspect of the query was
7
  incorrectly specified, or an error occures because the implementation is at fault. In the first case,
8
  the circumstance is signaled as REQUEST-ERROR, in order to indicate, that the client must correct the
9
  query. In the second case, the circumstance is signaled as a RUNTIME-ERROR wrapped around the unexpected
10
  initial condition.")
11
 
12
 (defgeneric error-task (condition)
13
   (:method ((condition t))
14
     nil))
15
 
16
 (define-condition spocq.e:error (simple-error)
17
   ((query
18
     :initarg :query :initarg :task :initform (or *task* *query*)
19
     :reader error-query :reader error-task
20
     :documentation "The query for which the error occured.")
21
    (expression
22
     :initarg :expression :initform nil
23
     :reader error-expression
24
     :documentation "Binds the expression which caused the error."))
25
   (:report spocq.e:report-condition)
26
   (:default-initargs :format-control ""))
27
 
28
 ;; the standard operators are plain functions
29
 (defmethod error-format-control ((error spocq.e:error))
30
   (simple-condition-format-control error))
31
 
32
 (defmethod error-format-arguments ((error spocq.e:error))
33
   (simple-condition-format-arguments error))
34
 
35
 #+(or)
36
 (defmethod print-object ((object spocq.e:error) (stream t))
37
   (if *print-escape*
38
       (call-next-method)
39
       (spocq.e:report-condition object stream)))
40
 
41
 #+(or)
42
 (defmethod print-object ((object spocq.e:error) (stream t))
43
   (call-next-method))
44
 
45
 (defmethod spocq.e:report-condition ((condition spocq.e:error) stream)
46
   (format stream "While processing~@[ query ~a~], an error was signaled~@[: ~?~]"
47
           (error-query condition)
48
           (error-format-control condition)
49
           (error-format-arguments condition)))
50
 
51
             
52
 (defgeneric error-task-agent (condition)
53
   (:method ((condition spocq.e:error))
54
     (let ((task (error-task condition))) (when task (task-agent task)))))
55
 
56
 (defgeneric error-task-id (condition)
57
   (:method ((condition spocq.e:error))
58
     (let ((task (error-task condition))) (when task (task-id task)))))
59
 
60
 (defgeneric error-user-id (condition)
61
   (:method ((condition spocq.e:error))
62
     (let ((task (error-task condition))) (when task (task-user-id task)))))
63
 
64
 (defgeneric error-repository-id (condition)
65
   (:method ((condition spocq.e:error))
66
     (let* ((task (error-task condition))
67
            (repository (when task (task-repository task))))
68
       (when repository (repository-id repository)))))
69
 
70
 (defgeneric error-content-type (condition)
71
   (:method ((condition spocq.e:error))
72
     (let ((task (error-task condition))) (when task (task-response-content-type task)))))
73
 
74
 (defgeneric error-request-exchange (condition)
75
   (:method ((condition spocq.e:error))
76
     (let ((task (error-task condition))) (when task (task-request-exchange task)))))
77
 
78
 (defgeneric error-routing-key (condition)
79
   (:method ((condition spocq.e:error))
80
     (let ((task (error-task condition))) (when task (task-request-routing-key task)))))
81
   
82
 
83
 (define-condition wrapped-condition-error (condition)
84
   ((condition
85
     :initarg :condition :initform nil
86
     :reader error-condition
87
     :documentation "Binds the wrapped runtime error.")))
88
 
89
 
90
 (define-condition spocq.e:runtime-error (spocq.e:error wrapped-condition-error)
91
   ()
92
   (:documentation "A wrapper around an 'inadvertent' runtime error to permit filtering and packaging as an
93
     error response. This applies to conditions such as compilation errors or reduction errors, in which
94
     cases it is not necessary to cycle the broker connection."))
95
 
96
 (defmethod spocq.e:report-condition ((condition spocq.e:runtime-error) stream)
97
   (call-next-method)
98
   (format stream "~@[The internal-condition was: ~a~]"
99
           (error-condition condition)))
100
 
101
 
102
 (define-condition spocq.e:request-error (spocq.e:error wrapped-condition-error)
103
   ((agent
104
     :initarg :agent :initform nil
105
     :reader error-agent)))
106
 
107
 (defun spocq.e:request-error (format-control &rest format-arguments)
108
   (error 'spocq.e:request-error
109
          :format-control format-control
110
          :format-arguments format-arguments))
111
 
112
 
113
 (define-condition spocq.e:argument-type-error (spocq.e:request-error type-error)
114
   ((operator
115
     :initarg :operator
116
     :reader type-error-operator))
117
   (:default-initargs
118
     :format-control "The argument value ~s to operator '~a' is not of the required '~a' type."))
119
 
120
 (defmethod error-format-arguments ((condition spocq.e:argument-type-error))
121
   (list (type-error-datum condition)
122
         (type-error-operator condition)
123
         (type-error-expected-type condition)))
124
 
125
 (defun spocq.e:argument-type-error (&rest args &key datum operator expected-type)
126
   (declare (ignore datum operator expected-type))
127
   (apply #'error 'spocq.e::argument-type-error args))
128
 
129
 (defmacro invalid-argument-type (operator variable type)
130
   `(error 'spocq.e:argument-type-error :datum ,variable :expected-type ',type
131
           :operator ',operator
132
           :format-control ,(format nil "~s: the ~a argument (~~s) must be of type ~a." operator variable type)
133
           :format-arguments (list ,variable)))
134
 
135
 (define-condition spocq.e::incommensurable-arguments-error (spocq.e:request-error type-error)
136
   ((operator
137
     :initarg :operator
138
     :reader type-error-operator))
139
   (:default-initargs
140
       :expected-type t
141
     :format-control "The argument values (~{~s, ~s~}) to operator '~a' are not comparable."))
142
 
143
 (defmethod error-format-arguments ((condition spocq.e::incommensurable-arguments-error))
144
   (list (type-error-datum condition)
145
         (type-error-operator condition)))
146
 
147
 (defun spocq.e::incommensurable-arguments-error (&rest args &key datum operator)
148
   (declare (ignore datum operator ))
149
   (apply #'error 'spocq.e::incommensurable-arguments-error args))
150
 
151
 
152
 
153
 (define-condition spocq.e:authorization-error (spocq.e:request-error)
154
   ((operation
155
     :initform nil :initarg :operation
156
     :reader error-operation)
157
    (location
158
     :initform nil :initarg :location
159
     :reader error-location)))
160
 
161
 (defun spocq.e:authorization-error (&rest args &key operation location agent)
162
   (declare (ignore operation location agent ))
163
   (apply #'error 'spocq.e:authorization-error args))
164
 
165
 
166
 (define-condition spocq.e:api-authorization-error (spocq.e:authorization-error)
167
   ()
168
   (:default-initargs
169
     :format-control "API access is not authorized: operation '~a'")
170
   (:documentation
171
    "An error which concerns the authorization afforded a process given its configuration"))
172
 
173
 (defmethod error-format-arguments ((condition spocq.e:api-authorization-error))
174
   (list (error-operation condition)))
175
 
176
 (defun spocq.e:api-authorization-error (&rest args)
177
   (apply #'error 'spocq.e:api-authorization-error args))
178
 
179
 
180
 (define-condition spocq.e:task-authorization-error (spocq.e:authorization-error)
181
   ()
182
   (:default-initargs
183
     :format-control "Resource access is not authorized: task '~a'('~a'): for '~a' to '~a'")
184
   (:documentation
185
    "An error which concerns the authorization to an given resource, for example a repository"))
186
 
187
 (defmethod error-format-arguments ((condition spocq.e:task-authorization-error))
188
   (list (error-task-id condition)
189
         (error-operation condition)
190
         (error-task-agent condition)
191
         (or (error-location condition) (error-repository-id condition))))
192
 
193
 (defun spocq.e:task-authorization-error (&rest args)
194
   (apply #'error 'spocq.e:task-authorization-error args))
195
 
196
 
197
 ;;; (spocq.e::cardinality-limit-error :operator 'cross-join :state '(:limit 3))
198
 (define-condition spocq.e::cardinality-limit-error (spocq.e:request-error type-error)
199
   ((operator
200
     :initform nil :initarg :operator
201
     :reader error-operator)
202
    (state
203
     :initarg :state
204
     :reader error-state)
205
    (dimensions
206
     :initarg :dimensions
207
     :reader error-dimensions))
208
   (:default-initargs
209
     :format-control "The operator ~a exceeded cardinality limits: ~s for ~s"))
210
 
211
 (defmethod error-format-arguments ((condition spocq.e::cardinality-limit-error))
212
   (list (error-operator condition)
213
         (error-state condition)
214
         (error-dimensions condition)))
215
 
216
 (defun spocq.e::cardinality-limit-error (&rest args &key operator state dimensions)
217
   (declare (ignore operator state dimensions))
218
   (apply #'error 'spocq.e::cardinality-limit-error args))
219
 
220
 
221
 
222
 (define-condition spocq.e:message-syntax-error (spocq.e:request-error)
223
   ((operation
224
     :initform nil :initarg :operation
225
     :reader error-operation)
226
    (token
227
     :initform nil :initarg :token
228
     :reader error-token)
229
    (byte-offset
230
     :initform nil :initarg :byte-offset
231
     :reader error-byte-offset)
232
    (line-offset
233
     :initform nil :initarg :line-offset
234
     :reader error-line-offset)
235
    (token-offset
236
     :initform nil :initarg :token-offset
237
     :reader error-token-offset))
238
   (:default-initargs
239
     :format-control "~@[(~a): ~]~@[task '~a': ~]~@[repository '~a': ~]Invalid message received :~@[~%Condition: ~a~]~@[~{~%failed to parse after '~a'~@[ at offset ~d~]~@[ on line ~d~]~@[ at position ~d~].~}~]~@[~%~a~]")
240
   (:documentation "A message-syntax-error describes a failure to parse a query message.
241
     If the information is available - eg from parse-sparql, it captures the state of the parser which
242
     describes the failure. The error message includes the query expression and progress information."))
243
 
244
 (defmethod error-format-arguments ((condition spocq.e:message-syntax-error))
245
   (list (error-operation condition)
246
         (error-task-id condition)
247
         (error-repository-id condition)
248
         (error-condition condition)
249
         (when (error-token condition)
250
           (list (error-token condition) (error-byte-offset condition) (error-line-number condition)
251
                 (error-token-offset condition)))
252
         (error-expression condition)))
253
 
254
 (defgeneric error-line-number (condition)
255
   (:method ((condition spocq.e:message-syntax-error))
256
     "If the condition captures the line offset, return 1+ to reflect the line number."
257
     (let ((offset (error-line-offset condition)))
258
       (when offset (1+ offset)))))
259
 
260
 (defun spocq.e:message-syntax-error (&rest args)
261
   (apply #'error 'spocq.e:message-syntax-error
262
          args))
263
 
264
 (defun spocq.e::message-length-error (message)
265
   (spocq.e::message-syntax-error :expression (string-truncate message 32)
266
                                  :operation "parse"
267
                                  :token (concatenate 'string ".." (subseq message (max 0 (- (length message) 30))))
268
                                  :byte-offset *query-maximum-length*
269
                                  :format-control 
270
                                  "~@[(~a): ~]~@[task '~a': ~]~@[repository '~a': ~]Oversized message received :~@[~%Condition: ~a~]~@[~{~%failed to parse after '~a'~@[ at offset ~d~]~@[ on line ~d~]~@[ at position ~d~].~}~]~@[~%~a~]"))
271
 
272
 (define-condition spocq.e:aggregate-projection-error (spocq.e:message-syntax-error )
273
   ())
274
 
275
 (defun spocq.e::aggregate-projection-error (&rest args)
276
   (apply #'error 'spocq.e::aggregate-projection-error
277
          args)) 
278
 
279
 (define-condition spocq.e::resource-error (spocq.e:error)
280
   ((identifier
281
     :initform nil :initarg :identifier
282
     :reader error-identifier))
283
   (:default-initargs
284
    :format-control  "identifier: '~a'~@[, task '~a'~]~@[. repository '~a'~].")
285
   (:documentation
286
    "An abstract error condition restive an individual resource."))
287
 
288
 (defmethod error-format-arguments ((condition spocq.e::resource-error))
289
   (list* (error-identifier condition)
290
          (error-task-id condition)
291
          (error-repository-id condition)
292
          (call-next-method)))
293
 
294
 (define-condition spocq.e:resource-not-found-error (spocq.e:resource-error)
295
   ()
296
   (:documentation
297
    "Indicate that a resource was not found at the given location in situations
298
     where the value would have been required for some operation - eg as a
299
     federation location, a provenance repository or as a source for secondary
300
     procesing intormation"))
301
 
302
 (defun spocq.e:resource-not-found-error (&rest args)
303
   (apply #'error 'spocq.e:resource-not-found-error
304
          args))
305
 
306
 (define-condition spocq.e::account-not-found-error (spocq.e:resource-not-found-error)
307
   ())
308
 
309
 (defun spocq.e::account-not-found-error (&rest args)
310
   (apply #'error 'spocq.e::account-not-found-error
311
          args))
312
 
313
 (define-condition spocq.e:repository-not-found-error (spocq.e:resource-not-found-error)
314
   ())
315
 
316
 (defun spocq.e:repository-not-found-error (&rest args)
317
   (apply #'error 'spocq.e:repository-not-found-error
318
          args))
319
 
320
 (define-condition spocq.e:revision-not-found-error (spocq.e:resource-not-found-error)
321
   ())
322
 
323
 (defun spocq.e:revision-not-found-error (&rest args)
324
   (apply #'error 'spocq.e:revision-not-found-error
325
          args))
326
 
327
 (define-condition spocq.e:revision-invalid-error (spocq.e:request-error type-error)
328
   ())
329
 
330
 (defun spocq.e:revision-invalid-error (&rest args)
331
   (apply #'error 'spocq.e:revision-invalid-error
332
          args))
333
 
334
 (define-condition spocq.e::view-not-found-error (spocq.e:resource-not-found-error)
335
   ())
336
 
337
 (defun spocq.e::view-not-found-error (&rest args)
338
   (apply #'error 'spocq.e::view-not-found-error
339
          args))
340
 
341
 
342
 (define-condition spocq.e:resource-found-error (spocq.e:resource-error)
343
   ()
344
   (:documentation
345
    "Indicate that a resource was found at the given location in situations
346
     where none should have been, for example for some operation which creates one"))
347
 
348
 (defun spocq.e::resource-found-error (&rest args)
349
   (apply #'error 'spocq.e:resource-found-error
350
          args))
351
 
352
 (define-condition spocq.e:library-resource-not-found (spocq.e:resource-not-found-error)
353
   ((library
354
     :initform nil :initarg :library
355
     :reader error-library))
356
   (:default-initargs
357
    :format-control  "~@[task: '~a', ~]~@[repository: '~a', ~]library: '~a', location: '~a'."))
358
 
359
 (defmethod error-format-arguments ((condition spocq.e:library-resource-not-found))
360
   (list (error-task-id condition)
361
         (error-repository-id condition)
362
         (error-library condition)
363
         (error-identifier condition)))
364
 
365
 (defun spocq.e:library-resource-not-found (&rest args)
366
   (apply #'error 'spocq.e::library-resource-not-found
367
          args))
368
 
369
    
370
 (define-condition spocq.e:graph-management-error (spocq.e:request-error)
371
   ((operation
372
     :initform nil :initarg :operation
373
     :reader error-operation))
374
   (:documentation "A protocol class to identify all conditions intentionally raised
375
     during a graph management operation:
376
     - when the source graph does not exist
377
     - when an invalid graph resource identifier is specified."))
378
 
379
 (defmethod error-format-arguments ((condition spocq.e:graph-management-error))
380
   (list* (error-operation condition)
381
          (call-next-method)))
382
 
383
 (define-condition spocq.e:graph-not-found-error (spocq.e:graph-management-error
384
                                                   spocq.e:resource-not-found-error)
385
   ()
386
   (:default-initargs
387
    :format-control  "graph not found: operation: ~a '~a' ~@[task '~a': ~]~@[repository '~a': ~]."))
388
 
389
 (defun spocq.e:graph-not-found-error (&rest args)
390
   (apply #'error 'spocq.e:graph-not-found-error
391
          args))
392
 
393
 (define-condition spocq.e:graph-found-error (spocq.e:graph-management-error
394
                                               spocq.e:resource-found-error)
395
   ()
396
   (:default-initargs
397
    :format-control  "graph exists: operation: ~a '~a' ~@[task '~a': ~]~@[repository '~a': ~]."))
398
 
399
 (defun spocq.e::graph-found-error (&rest args)
400
   (apply #'error 'spocq.e:graph-found-error
401
          args))
402
 
403
 (define-condition spocq.e:invalid-graph-error (spocq.e:graph-management-error
404
                                                 spocq.e:resource-error)
405
   ()
406
   (:default-initargs
407
    :format-control  "invalid graph resource: ~@[task '~a': ~]~@[repository '~a': ~]operation: ~a '~a'."))
408
 
409
 (defun spocq.e:invalid-graph-error (&rest args)
410
   (apply #'error 'spocq.e:invalid-graph-error
411
          args))
412
 
413
 
414
 (define-condition invalid-token-error (spocq.e:request-error)
415
   ())
416
 
417
 (defmethod error-format-arguments ((condition invalid-token-error))
418
   (list (error-task-id condition)
419
         (error-repository-id condition)
420
         (error-expression condition)))
421
 
422
 
423
 (define-condition spocq.e:unbound-prefix-error (invalid-token-error)
424
   ()
425
   (:default-initargs
426
     :format-control "~@[task '~a': ~]~@[repository '~a': ~]Unbound prefix: '~a'."))
427
 
428
 (defun spocq.e:unbound-prefix-error (&rest args)
429
   (apply #'error 'spocq.e:unbound-prefix-error
430
          args))
431
 
432
 (define-condition spocq.e::vocabulary-error (invalid-token-error)
433
   ()
434
   (:default-initargs
435
     :format-control "~@[task '~a': ~]~@[repository '~a': ~]Invalid vocabulary term: '~a'."))
436
 
437
 (defun spocq.e::vocabulary-error (&rest args)
438
   (apply #'error 'spocq.e::vocabulary-error
439
          args))
440
 
441
 
442
 
443
 (define-condition spocq.e:compilation-error (spocq.e:request-error wrapped-condition-error)
444
   ()
445
   (:default-initargs
446
     :format-control "Expression compilation failed :~%Condition: ~a~%Expression: ~s")
447
   (:documentation "Signaled when an attempt to compile one of a query's constituent functions -
448
     bgp predicate, predicate, or reduction, fails or issues a warning."))
449
 
450
 (defmethod error-format-arguments ((condition spocq.e:compilation-error))
451
   (list (error-condition condition) (error-expression condition)))
452
 
453
 (defun spocq.e:compilation-error (&rest args &key (expression nil) (condition nil) &allow-other-keys)
454
   (apply #'error 'spocq.e:compilation-error
455
          :expression expression
456
          :condition (or condition (make-condition 'unknown-compilation-error))
457
          args))
458
 
459
 (define-condition unknown-compilation-error (spocq.e:compilation-error)
460
   ()
461
   (:report (lambda (c stream)
462
              (declare (ignore c))
463
              (write-string "A compilation error occurred without further information." stream))))
464
 
465
 
466
 (define-condition spocq.e:undefined-variable-error (spocq.e:compilation-error)
467
   ((variables :initarg :variables :reader error-variables))
468
   (:default-initargs
469
     :format-control "The variable~p ~s ~:[are~;is~] not defined~@[ in ~s~]."))
470
 
471
 (defmethod error-format-arguments ((condition spocq.e:undefined-variable-error))
472
   (let* ((variables (error-variables condition))
473
          (count (length variables)))
474
     (list count
475
           (if (rest variables) variables (first variables))
476
           (= count 1)
477
           (error-expression condition))))
478
 
479
 (defun spocq.e:undefined-variable-error (&key name (expression name))
480
   (error 'spocq.e:undefined-variable-error :expression expression))
481
 
482
 
483
 (define-condition spocq.e:redefined-variable-error (spocq.e:compilation-error)
484
   ((variables :initarg :variables :reader error-variables))
485
   (:default-initargs
486
     :format-control "The variable~p ~a ~:[are~;is~] already defined~@[ in ~s~].")
487
   (:documentation
488
    "Indicate this as a compilation error, even though it can be deferred to extend clause execution."))
489
 
490
 (defmethod error-format-arguments ((condition spocq.e:redefined-variable-error))
491
   (let* ((variables (error-variables condition))
492
          (count (length variables)))
493
     (list count
494
           (if (rest variables) variables (first variables))
495
           (= count 1)
496
           (error-expression condition))))
497
 
498
 (defun spocq.e:redefined-variable-error (&rest args &key variables expression)
499
   (declare (ignore variables expression))
500
   (apply #'error 'spocq.e:redefined-variable-error args))
501
 
502
 
503
 (define-condition spocq.e:quota-error (spocq.e:request-error)
504
   ((detail
505
     :initform nil :initarg :detail :reader condition-detail))
506
   (:report (lambda (c stream)
507
              (format stream "Expression reduction exceeded its resources~@[: ~a~]."
508
                      (condition-detail c))))
509
   (:documentation "Signaled when a query reduction exceeds its resources."))
510
 
511
 (define-condition spocq.e:timeout-error (spocq.e:quota-error)
512
   ()
513
   (:report (lambda (c stream)
514
              (format stream "Expression reduction timed out: ~a~@[: ~a~]."
515
                      (error-query c) (condition-detail c))))
516
   (:documentation "Signaled when a query reduction times out."))
517
 
518
 (defun spocq.e::timeout-error (&rest args)
519
   (apply #'error 'spocq.e::timeout-error args))
520
 
521
 (define-condition spocq.e:abort-error (spocq.e:runtime-error)
522
   ()
523
   (:report (lambda (c stream)
524
              (format stream "Expression reduction aborted: ~a."
525
                      (error-query c))))
526
   (:documentation "Signaled when a query reduction is aborted."))
527
 
528
 (defun spocq.e:abort-error (&rest args)
529
   (apply #'error 'spocq.e:abort-error args))
530
 
531
 
532
 (defgeneric task-errors (task)
533
   (:documentation "Returns the message channel into which to place error messages
534
    respective processing a given task. outside of a task environment, returns
535
    the global condition channel")
536
   (:method ((task t))
537
     *error-condition-channel*))
538
 
539
 (defun generate-error-note (condition &key (task *query*) (channel (task-errors task)))
540
   (channel-put channel (cons task condition)))
541
 
542
 
543
 ;;;
544
 (define-condition spocq.e:constraint-violation (spocq.e:request-error)
545
   ())
546
 (defun spocq.e:constraint-violation (&rest args)
547
   (apply #'error 'spocq.e:constraint-violation args))
548
 
549
 ;;;
550
 ;;; protected operations
551
 
552
 (defvar *compilation-lock*
553
   #+sbcl nil                            ; sbcl has a global lock for the compiler
554
   ;; really tdb
555
   #-sbcl (bt:make-lock "spocq compilation"))
556
 
557
 (defun spocq-compile (lambda-expression)
558
   "Compile EXPRESSION with an established error and warning handler. If the compilation
559
  succeeds, return the result. If an error occurs, wrap it in a compilation-error
560
  and resignal that. If the compiler has suppressed and returned the error itself, 
561
  treat that the same as a signaled one."
562
 
563
   (flet ((do-compile ()
564
            (multiple-value-bind (function condition-p serious-condition-p)
565
                                 (handler-case (compile nil lambda-expression)
566
                                   ((or warning error) (c)
567
                                    (write-log :warn "compilation error: ~a" c) ;; macro is not around yet
568
                                    (spocq.e:compilation-error :condition c
569
                                                               :expression lambda-expression)))
570
              (declare (ignore condition-p))
571
              (if serious-condition-p
572
                (spocq.e:compilation-error :expression lambda-expression)
573
                function))))
574
     (if *compilation-lock*
575
       (bt:with-lock-held (*compilation-lock*) (do-compile))
576
       (do-compile))))