Coverage report: /development/source/library/org/datagraph/spocq-shard/src/odbc/service.lisp

KindCoveredAll%
expression0256 0.0
branch010 0.0
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 "service operation implementation for odbc-based sql processing.")
6
 
7
 (defclass hydra:|ODBCView| (hydra:|Operation|)
8
   ((sql-cache
9
     :initform (make-registry :test 'eql)
10
     :reader repository-sql-cache)
11
    (connection
12
     :initform nil :initarg :connection
13
     :reader get-repository-connection
14
     :writer setf-repository-connection)))
15
 
16
 (defclass hydra:|PostgresView|  (hydra:|ODBCView|)
17
   ())
18
 
19
 (defmethod call-with-repository-connection (op (repository hydra:|ODBCView|))
20
   (let* ((odbc-uri (repository-uri repository))
21
          (driver (spocq:odbc-uri-driver odbc-uri))
22
          (uri-authority (spocq:odbc-uri-authority odbc-uri))
23
          (authority (when uri-authority (authority uri-authority)))
24
          (user (if authority (agent-name authority) (spocq:odbc-uri-user odbc-uri)))
25
          (password (if authority (agent-password authority) (spocq:odbc-uri-password odbc-uri))))
26
     (clsql:with-database (db-connection (list driver user password)
27
                                         :database-type :odbc :pool t :if-exists :new)
28
       (funcall op db-connection))))
29
 
30
        
31
 (defmethod repository-connection ((repository hydra:|ODBCView|))
32
   (or (get-repository-connection repository)
33
       (setf-repository-connection (let* ((odbc (repository-uri repository))
34
                                          (uri-authority (spocq:odbc-uri-authority odbc))
35
                                          (authority (when uri-authority (authority uri-authority)))
36
                                          (user (if authority (agent-name authority) (spocq:odbc-uri-user odbc)))
37
                                          (password (if authority (agent-password authority) (spocq:odbc-uri-password odbc))))
38
                                     (clsql:connect `(;;,(spocq:odbc-uri-database odbc)
39
                                                      ,(spocq:odbc-uri-driver odbc)
40
                                                      ,user
41
                                                      ,password)
42
                                                    :database-type :odbc))
43
                                   repository)))
44
 
45
 
46
 
47
 ;;; remote service operations
48
 
49
 (defmethod spocq.e:service ((service-repository hydra:|ODBCView|) (query-expression t) &key (verbose t) user-id query-text)
50
   "For external view processing, compute a generator which will start an external process to run
51
   the remote query as a view and intern the result solution stream."
52
   (declare (ignore user-id query-text))
53
   (authorize-service-request *task* service-repository)
54
   (odbc-view-generator service-repository (expression-dimensions query-expression)
55
                        query-expression
56
                        :verbose verbose))
57
 
58
 (defmethod repository-sparql-sql ((repository hydra:|ODBCView|) expression)
59
   (let ((entry (get-registry expression (repository-sql-cache repository))))
60
     (unless entry
61
       (setf entry (multiple-value-list (call-next-method)))
62
       (setf (get-registry expression (repository-sql-cache repository)) entry))
63
     (apply #'values entry)))
64
 
65
 (defun odbc-view-generator (repository pattern-dimensions query-expression &key verbose)
66
   "Construct a generator which will delegate request/response processing for a remote view
67
    to an external thread.
68
    In the event of error, unless verbose, suppress it and proceed with a table solution field.
69
    When verbose, decline to handle the error and delegate it to the context."
70
   (handler-bind ((error (lambda (c)
71
                           (log-warn "odbc service view failure: ~a: ~a" repository c)
72
                           (unless verbose
73
                             (return-from odbc-view-generator
74
                               (singleton-generator pattern-dimensions))))))
75
     ;;(bt:with-lock-held ((repository-lock repository))
76
     (multiple-value-bind (sql-query sql-environment)
77
                          (repository-sparql-sql repository query-expression)
78
       (with-repository-connection (db-connection repository)
79
         (multiple-value-bind (sql-solutions attribute-names)
80
                              (clsql:query sql-query :database db-connection)
81
           (let* ((count (length sql-solutions))
82
                  ;; either known results, or respective undistinguished variables
83
                  (sql-dimensions (loop for attribute in attribute-names
84
                                    for dimension = (cond ((sql-attribute-variable attribute sql-environment))
85
                                                          (t
86
                                                           (warn "attribute not in sql environment: ~s: ~s"
87
                                                                 attribute
88
                                                                 (sql-environment-av-map sql-environment))
89
                                                           nil))
90
                                    collect (or dimension (make-variable attribute)))))
91
             (trace-algebra odbc-view-generator :sql-env sql-environment :pd pattern-dimensions :sd sql-dimensions)
92
             (unless (equal pattern-dimensions sql-dimensions)
93
               (setf sql-solutions (loop for solution in sql-solutions
94
                                     collect (loop for pattern-dimension in pattern-dimensions
95
                                               collect (loop for term in solution for sql-dimension in sql-dimensions
96
                                                         when (eq pattern-dimension sql-dimension)
97
                                                         return term
98
                                                         finally (return (spocq:make-unbound-variable pattern-dimension)))))))
99
             (typecase *transaction*
100
               (matrix-transaction
101
                (let ((result-field (make-matrix-field :dimensions sql-dimensions :row-count count)))
102
                  (set-solution-field-solutions result-field sql-solutions)
103
                  (complete-field-data result-field)
104
                  result-field))
105
               (t
106
                (let ((result-channel (make-channel :name (list 'spocq.a:|service| (task-id *query*))
107
                                                    :dimensions pattern-dimensions)))
108
                  (make-solution-generator :operator 'spocq.a:|service|
109
                                           :dimensions pattern-dimensions
110
                                           :expression (list #'run-service-thread result-channel sql-solutions pattern-dimensions)
111
                                           :channel result-channel
112
                                           :constituents ()))))))))));)
113
 
114
 (defmethod run-sip-service-step ((repository hydra:|ODBCView|) destination pattern-expression bindings &rest args)
115
   "A postgres repository handles a service operation w/ sip by translating the sparql expression into SQL,
116
    serializing that wrt the given solution, executing the SQL query through a remote connection, interning the
117
    response, and emitting it to the given destination."
118
   (declare (ignore args))
119
   (authorize-service-request *task* repository)
120
   (multiple-value-bind (sql-query sql-environment)
121
                        (repository-sparql-sql repository pattern-expression)
122
     (with-repository-connection (db-connection repository)
123
       (multiple-value-bind (sql-solutions attribute-names)
124
                            (clsql:query sql-query :database db-connection)
125
         (let* ((count (length sql-solutions))
126
                (sql-dimensions (loop for attribute in attribute-names
127
                                  for dimension = (cond ((sql-attribute-variable attribute sql-environment))
128
                                                        (t
129
                                                         (warn "attribute not in sql environment: ~s" attribute)
130
                                                         nil))
131
                                  collect (or dimension (cons-variable attribute))))
132
                (result-dimensions (channel-dimensions destination))
133
                (width (length result-dimensions))
134
                (page (new-field-page destination count width)))
135
           (trace-algebra odbc-view-generator :sql-env sql-environment :rd result-dimensions :sd sql-dimensions)
136
           (cond ((equal result-dimensions sql-dimensions)
137
                  (term-number-field sql-solutions :field page))
138
                 (t
139
                  (let ((interned-sip-solution (loop for (nil . term) in bindings
140
                                                 collect (rdfcache-object-term-number *transaction* term))))
141
                    (transaction-intern-shuffeled-field *transaction* sql-solutions sql-dimensions result-dimensions :field page :partial t)
142
                    (loop for i below count
143
                      do (loop for j from 0
144
                           for dimension in result-dimensions
145
                           ;; if the dimension was in the sip and not in the view, the assert the term
146
                           unless (find dimension sql-dimensions)
147
                           do (loop for (sip-dimension . nil) in bindings
148
                                for term-number in interned-sip-solution
149
                                when (eq dimension sip-dimension)
150
                                do (setf (aref page i j) term-number)))))))
151
           (trace-data run-sip-service-step :page page (term-value-field page))
152
           (put-field-page destination page)
153
           count)))))