Hi all,

Using 6.0.1,  webserver and postgresql.

Got a weird problem:

I have a servlet that uses Postgresql's tsquery function to do a text search. tsquery requires a particular syntax in its search string, but I can't guarantee that the provided string will be valid (too many variations), so the only thing I can do is try it and see what happens. When the search string is valid, everything is fine.

However, when the search string syntax is invalid I get the following exception:

length: contract violation
  expected: list?
  given: #f

Stack trace:

activity/search at:
  line 645, column 0, in file <redacted>\lookup.ss
<unknown procedure> at:
  line 255, column 18, in file C:\Program 
Files\Racket\collects\racket\contract\private\arrow-val-first.rkt
<unknown procedure> at:
  line 255, column 18, in file C:\Program 
Files\Racket\collects\racket\contract\private\arrow-val-first.rkt
<unknown procedure> at:
  line 58, column 2, in file C:\Program 
Files\Racket\share\pkgs\web-server-lib\web-server\dispatchers\dispatch-servlets.rkt
select-handler/no-breaks at:
  line 162, column 2, in file C:\Program 
Files\Racket\collects\racket\private\more-scheme.rkt
<unknown procedure> at:
  line 112, column 8, in file C:\Program 
Files\Racket\share\pkgs\web-server-lib\web-server\private\dispatch-server-unit.rkt

Yes, this is on Windows, but the same happens on Linux.

Some exploration has determined that the servlet exception is coming from query-rows. The with-database macro shown below in the 2nd listing is in (exported from) a separate file which included into #:servlet-namespace in serve/servlet because it contains a large number of utility functions used by all my servlets.


 =====  lookup.ss  =====

(define (activity/search request)
  (let* [
         (tid     (make-log-id))
         (params  (request-bindings request))
         (inquiry (exists-binding? 'query params))

         (result  #f)
         (success #f)
         (dberror #f)
        ]

    ; validate request
    (unless inquiry
      (log-write tid 'activity/search "parameters" params )
      (send/back (response/parameters "parameters: query string")))

    ; get request parameters
    (set! inquiry (extract-binding/single 'query params))

    ; log query
    (log-write tid 'activity/search "query" inquiry)

    ; database
    (with-database db errors to dberror
       (let [
             (sql-cmd (string-join '(
                             "select * from activities"
                             "   where to_tsvector(activity)"
                             "         @@ to_tsquery($1)"
                             )))
            ]

         (set! result (query-rows db sql-cmd inquiry))

         ; valid result?
         (when (and result
                    (not (empty? result))
                    (valid-data? result))
           (set! success #t))
         ))

    ; log result
    (log-write tid 'activity/search (if success "success" "failure")
               inquiry (length result) dberror)

   ; send response
    (let [
          (retval (make-hash `((success . ,success)
                               (data    . #f)
                               (error   . ,dberror))
                             ))
         ]
      (when success
         (hash-set! retval 'data
                    (for/list [(row result)]
                      (activity->json row)
                      ))
         )

      (send/back (response/json retval))
      )

    ))



 =====  utility.ss  =====

(define-syntax with-database
  (syntax-rules (errors to)
    ((with-database dbc errors to errmsg body ...)
     ; -- start template
     (let/ec fail-network
       (with-handlers [
                       (exn:fail:network?
                        (lambda (e)
                          (set! errmsg "database connection error")
                          (fail-network)))
                      ]
         (let [
               (dbc (connect-database))
              ]
           (let/ec fail-sql
             (with-handlers [
                             (exn:fail:sql?
                              (lambda (e)
                                (let [(info (exn:fail:sql-info e))]
                                  (set! errmsg (cdr (assoc 'message info)))
                                  (fail-sql))))
                            ]
               ;----------
                 body ...
               ;----------

               )
             (disconnect dbc))
           )))
     ; -- end template
     )))


 =================================


If I run the exact same database query code stand alone in a test app - i.e. without the surrounding servlet baggage - and give it an invalid search string, it works as expected and returns a database error: "syntax error in tsquery: \"<the invalid string>\"".

I don't understand why the query code is throwing a LIST? contract error and why it happens only when run in a servlet. I also don't know what to do about it. Any enlightenment and/or suggestions would be greatly appreciated.

Thanks,
George


____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to