sql - 如何避免在使用 haskell 解析 sql 时将 WHERE 视为属性

标签 sql parsing haskell parsec

我正在使用 Parsec 在 Haskell 中解析 SQL。如何确保带有 where 子句的语句不会将 WHERE 视为表名?在下面找到我的编码的一部分。 p_Combination 有效,但它将 WHERE 视为属性列表的一部分,而不是 where 子句。

--- from clause 
data Table_clause = Table {table_name :: String, alias :: Maybe String} deriving Show
p_Table_clause:: Parser Table_clause
p_Table_clause = do
    t <- word
    skipMany (space <?> "require space at the Table clause")
    a <- optionMaybe (many1 (alphaNum)) <?> "aliase for table or nothing"
    return $ Table t a

newtype From_clause = From [Table_clause] deriving Show         
p_From_clause :: Parser From_clause
p_From_clause = do
    string "FROM" <?> "From";
    skipMany1 (space <?> "space in the from clause ")
    x <- sepBy p_Table_clause (many1(char ',' <|> space))
    return $ From x

-- where clause conditions elements 
data WhereClause = WhereFCondi String deriving Show
p_WhereClause :: Parser WhereClause 
p_WhereClause = do
    string "WHERE"
    skipMany1 space
    x <- word
    return $ WhereFCondi x

data Combination = FromWhere From_clause (Maybe WhereClause) deriving Show
p_Combination :: Parser Combination
p_Combination = do
    x <- p_From_clause
    skipMany1 space
    y <- optionMaybe p_WhereClause
    return $ FromWhere x y

最佳答案

普通的 SQL 解析器有很多保留字,而且它们通常不区分上下文。也就是说,即使 where 可能是明确的,也不允许仅仅因为它是保留的。我猜大多数实现都是通过首先在概念上独立于解析词法化标记的阶段对源进行词法分析来实现这一点的,但我们不需要使用 Parsec 来做到这一点。

通常我们使用 Parsec 的方法是使用 Text.Parsec.Token .要使用它,您首先要创建一个 LanguageDef 来定义您打算解析的语言的一些基本特征:注释如何工作、保留字、是否区分大小写等。然后您使用 makeTokenParser 以获得包含为该语言量身定制的功能的记录。例如,identifier 不会匹配任何保留字,他们都小心地在必要的地方要求空格,当他们跳过空格时,注释也会被跳过。


如果您想继续使用当前的方法,只使用 Parsec 基元,您可能需要查看 notFollowedBy .这并不完全符合您的代码的作用,但它应该提供一些关于如何使用它的灵感:

string "FROM" >> many1 space
tableName <- many1 alphaNum <* many1 space
aliasName <- optionMaybe $ notFollowedBy (string "WHERE" >> many1 space)
                        >> many1 alphaNum <* many1 space

本质上:

  1. 解析 FROM,然后是空格。
  2. 解析表名,然后解析空格。
  3. 如果 WHERE 后跟空格不是下一个,则解析别名然后是空格。

关于sql - 如何避免在使用 haskell 解析 sql 时将 WHERE 视为属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24580176/

相关文章:

linux - 如何解析 netstat 命令以便从中获取进程名称和 PID?

haskell - 为什么我们需要单子(monad)?

mysql - 如何写一个sql语句从所有用户中获取一个值?

java - hibernate join fetch 不会获取所有子项

SQL:在没有 INNER JOIN 的情况下比较条目部分的两个表

file - 如何读取 elixir mix 项目的配置文件

mysql - 如何定位和显示我的 .Net 页面的特定数据库字段

parsing - 在 Rust 中反序列化键 = 值字符串列表的最佳方法

haskell - 将文件读入列表

haskell - GHCi 7.8.3 中的评估