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??