Slide 1

Slide 1 text

@LukasFittl Hacking PostgreSQL to Gain SQL Parsing Superpowers @LukasFittl

Slide 2

Slide 2 text

@LukasFittl Parsing SQL

Slide 3

Slide 3 text

@LukasFittl SELECT  *  FROM  x  WHERE  z  =  1

Slide 4

Slide 4 text

@LukasFittl http://xkcd.com/208/

Slide 5

Slide 5 text

@LukasFittl PostgreSQL

Slide 6

Slide 6 text

@LukasFittl EXPLAIN  (PARSETREE  TRUE)      SELECT  *  FROM  x  WHERE  y  =  1 Unfortunately doesn’t exist.

Slide 7

Slide 7 text

@LukasFittl Parse Statement raw_parse(..) pg_catalog Rewrite Query Query Planner Execute How PostgreSQL runs a Query:

Slide 8

Slide 8 text

@LukasFittl tree = raw_parser(query_str); str = nodeToString(tree); printf(str); ({SELECT  :distinctClause  <>                    :intoClause  <>                    :targetList  (                        {RESTARGET                            :name  <>                            :indirection  <>                            :val  {COLUMNREF  :fields  ({A_STAR})  :location  7}                            :location  7})                    :fromClause  (                        {RANGEVAR                            :schemaname  <>                            :relname  x                            :inhOpt  2                            :relpersistence  p                            :alias  <>                            :location  14})                    :whereClause  {AEXPR    :name  (“=")                        :lexpr  {COLUMNREF  :fields  ("y")  :location  22}                        :rexpr  {PARAMREF  :number  0  :location  26}                        :location  24}                    :groupClause  <>                    :havingClause  <>                    :windowClause  <>  

Slide 9

Slide 9 text

@LukasFittl Parse Statement raw_parse(..) pg_catalog Rewrite Query Query Planner Execute

Slide 10

Slide 10 text

@LukasFittl PgQuery._raw_parse( “SELECT * FROM x WHERE y = 1”) ({SELECT  :distinctClause  <>                    :intoClause  <>                    :targetList  (                        {RESTARGET                            :name  <>                            :indirection  <>                            :val  {COLUMNREF  :fields  ({A_STAR})  :location  7}                            :location  7})                    :fromClause  (                        {RANGEVAR                            :schemaname  <>                            :relname  x                            :inhOpt  2                            :relpersistence  p                            :alias  <>                            :location  14})                    :whereClause  {AEXPR    :name  (“=")                        :lexpr  {COLUMNREF  :fields  ("y")  :location  22}                        :rexpr  {PARAMREF  :number  0  :location  26}                        :location  24}                    :groupClause  <>                    :havingClause  <>                    :windowClause  <>                    :valuesLists  <>  

Slide 11

Slide 11 text

@LukasFittl PgQuery._raw_parse( “SELECT * FROM x WHERE y = 1”) [{     "SelectStmt":  {       "targetList":  [{         "ResTarget":  {           "val":  {             "ColumnRef":  {               "fields":  [{                 "A_Star":  {}               }],               "location":  7             }           },           "location":  7         }       }],       "fromClause":  [{         "RangeVar":  {           "relname":  "x",           "inhOpt":  2,           "relpersistence":  "p",           "location":  14         }       }],       "whereClause":  {         "A_Expr":  {  

Slide 12

Slide 12 text

@LukasFittl github.com/lfittl/pg_query

Slide 13

Slide 13 text

@LukasFittl De-Parsing SQL

Slide 14

Slide 14 text

@LukasFittl SELECT * FROM the_table SELECT * FROM a_better_table

Slide 15

Slide 15 text

@LukasFittl q  =  PgQuery.parse(‘SELECT  *  FROM  the_table’)   =>   [{"SelectStmt"  =>  {      "targetList"  =>[…],      "fromClause"  =>  [{          "RangeVar"  =>  {       "relname"  =>  “the_table",              …          }      }]   }}]   q.tree[0][‘SelectStmt']['fromClause'][0][‘RangeVar'] ['relname']  =  ‘the_other_table'   q.deparse   =>  "SELECT  *  FROM  \"the_other_table\"

Slide 16

Slide 16 text

@LukasFittl Don’t like JSON?

Slide 17

Slide 17 text

@LukasFittl pg_query_go package  main   import  (      "github.com/lfittl/pg_query_go"   )   func  main()  {      tree,  err  :=  pg_query.Parse("SELECT  1")      if  err  !=  nil  {          panic(err);      }      …   }

Slide 18

Slide 18 text

@LukasFittl pg_query.ParsetreeList{          Statements:  []nodes.Node{              nodes.SelectStmt{                  TargetList:  []nodes.Node{                      nodes.ResTarget{                          Val:  nodes.A_Const{                              Type:  "integer",                              Val:  nodes.Value{                                  Type:  nodes.T_Integer,                                  Ival:  1,                              },                              Location:  7,                          },                          Location:  7,                      },                  },              },          }, tree  :=  pg_query.Parse(“SELECT  1")

Slide 19

Slide 19 text

@LukasFittl Other Languages C/C++: libpg_query Go: pg_query_go Node.js: pg-query-parser Not yet: Python, Java, [?]

Slide 20

Slide 20 text

@LukasFittl Shameless Plug: github.com/citusdata/citus Open-source, distributed PostgreSQL

Slide 21

Slide 21 text

@LukasFittl Thank You! github.com/lfittl/pg_query