0

I'm using the direct-sqlite package for Haskell to query an SQLite database. I need REGEXP matching, so I've constructed a Haskell function that implements the functionality, and inserted it into the database connection.

import Text.Regex.Base.RegexLike
import qualified Text.Regex.PCRE.ByteString as PCRE
import Database.SQLite3

data UmeQuery = UmeQuery Text [SQLData]  deriving Show
data Segment = Segment SegmentLabel SegmentStart SegmentEnd Session LabelType Checksum deriving (Show)

runUmeQuery :: UmeQuery -> FilePath -> IO [Segment] 
runUmeQuery eq  dbFile = do
    conn <- open $ pack dbFile
    res <- runUmeQuery' eq conn
    return res

runUmeQuery' :: UmeQuery -> Database -> IO [Segment] 
runUmeQuery' (UmeQuery q args) conn = do
    statement <- prepare conn q
    createFunction conn "regexp" (Just 2) True sqlRegexp
    bind statement args
    res <- fmap reverse $ getRows statement []
    Database.SQLite3.finalize statement
    close conn
    return res

getRows :: Statement  -> [Segment] -> IO [Segment]
getRows stmt  acc = do
  r <- step stmt
  case r of
    Done -> return acc
    Row -> do
      sess <- columnText stmt 0
      lt <- columnText stmt 1
      start <- columnDouble stmt 3
      end <- columnDouble stmt 4
      label <- columnText stmt 5
      checksum <- columnText stmt 6
      getRows stmt ((Segment label start end sess lt checksum):acc)


sqlRegexp :: FuncContext -> FuncArgs -> IO ()
sqlRegexp ctx args = do
    reg <- fmap encodeUtf8 $ funcArgText args 0
    text <- fmap encodeUtf8 $ funcArgText args 1
    res <- pcreRegex reg text
    funcResultInt64 ctx res
    where
        pcreRegex reg b = do
            reC <- pcreCompile reg
            re <- case reC of
                (Right r) -> return r
                (Left (_,e) ) -> fail e
            reE <- PCRE.execute re b
            case reE of
                (Right (Just _)) -> return (1 :: Int64)
                (Right (Nothing)) -> return (0 :: Int64)
                (Left (_,e)) -> fail e -- Not a good idea maybe, but I have no use for error messages.
            where pcreCompile = PCRE.compile defaultCompOpt defaultExecOpt

So, basically, the query functions opens a connection, inserts a "regexp" function and executes a query (in a data type). This is according to the manual:

The REGEXP operator is a special syntax for the regexp() user function. No regexp() user function is defined by default and so use of the REGEXP operator will normally result in an error message. If an application-defined SQL function named "regexp" is added at run-time, then the "X REGEXP Y" operator will be implemented as a call to "regexp(Y,X)". https://www.sqlite.org/lang_expr.html#like

Now, the problem is that the function is not available in queries:

> let b = UmeQuery (pack "select * from segments where label REGEXP '.*';") []
*Phonetic.Database.UmeQuery
> out <- runUmeQuery b "./umecore-hs/testdata/umetest.umedb"
*** Exception: SQLite3 returned ErrorError while attempting to perform prepare "select * from segments where label REGEXP '.*';": no such function: REGEXP

How do I make it available??

2
  • 1
    I don't know Haskell, but this code looks as if it's preparing the statement before installing the function. Commented Jul 11, 2016 at 7:41
  • You're right! Of course! Please forgive my stupidity! That works! Commented Jul 11, 2016 at 8:04

1 Answer 1

0

I don't know Haskell, but this code looks as if it's preparing the statement before installing the function. – CL. 24 mins ago

Silly me.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.