際際滷

際際滷Share a Scribd company logo
SQLQL とは。SQLQL とは。
2019/04/24 y恙Rails#8
@yancya
Powered by Rabbit 2.2.2 and COZMIXNG
@yancya の徭失B初
Rubyist, SQList
秤I尖芦畠_隠屶址平
児云議なこと
Ruby on Rails でアプリケ`ショ
ンを_kしていて巌樋來になる
パタ`ン
Rails に鬉靴討い覆ぴO
Rails のル`ルに惄辰討い覆ぴO
SQLQL とは
https://somehost/sqlql みたいな
URL に SQL を僕佚すると、SQL
g佩Y惚の JSON が卦ってくると
いう古廷
SQL のg佩Y惚が JSON と
は
SELECT id, name FROM user
ってやったら
[{"id":10,"name":"yancya"},
{"id":11,"name":"testuser"}]
みたいなのが卦ってくる
僕佚すると、とは
猟忖宥り、リクエストにそのまま
SQL を根める
curl -X GET 
-H 'Authorization: Token 6f916ae6-8472-463a-9808-6af19e459541' 
-F "haute_couture[query]=select id, name from users" 
https://sqlql-sample-yancya.herokuapp.com/haute_couture
J^している
している。そして、J^されたユ`
ザ`に歌孚がS辛されているレコ`
ドのみが卦ってくる
◎ は secretman というユ`ザ`の
ト`クンを聞ったリクエスト
curl -X GET 
-H 'Authorization: Token 4f3326a4-b900-4624-af58-87e8f363dee6' 
-F "haute_couture[query]=select id, name from users" 
https://sqlql-sample-yancya.herokuapp.com/haute_couture
S辛されているレコ`ドのみ
が
リクエストしたユ`ザ`のJ辛に
じたレスポンスとなる
secretman のリクエストには
secretman のレコ`ドが根まれる
[{"id":10,"name":"yancya"},
{"id":11,"name":"testuser"},
{"id":14,"name":"secretman"}]
ネストした佩は卦せなくo
い
SQL に JSON をMむv方がある
SELECT u.id, u.name, json_agg(c.content) as comments
FROM users AS u
LEFT OUTER JOIN comments AS c ON u.id = user_id
GROUP BY 1, 2
Array 秘りの JSON の箭
curl -X GET 
-H 'Authorization: Token 4f3326a4-b900-4624-af58-87e8f363dee6' 
-F "haute_couture[query]=
SELECT u.id, u.name, json_agg(c.content) as comments 
FROM users AS u 
LEFT OUTER JOIN comments AS c ON u.id = user_id 
GROUP BY 1, 2"
https://sqlql-sample-yancya.herokuapp.com/haute_couture
Array 秘りの JSON の箭
[{"id":11,"name":"testuser","comments":["it is not secret"]},
{"id":14,"name":"secretman","comments":[null]},
{"id":10,"name":"yancya","comments":["hoge", "fuga", "piyo"]}]
どうやってgFしているのか
リクエストのクエリを CTE(WITH)
の嶄に托めzんでいる
module HauteCouture
def self.find_by_sql(query:, user:)
ActiveRecord::Base.connection.execute(<<~SQL).first['result'] || '[]'
WITH users AS (#{user.for_haute_couture_sql})
, comments AS (#{Comment.for_haute_couture(user).to_sql})
, t AS (#{query})
SELECT JSON_AGG(t) AS result FROM t
SQL
end
end
どうやってgFしているのか
# User#for_haute_couture_sql
def for_haute_couture_sql
base = User.select(:id, :name, :created_at, :updated_at)
base.where(id: id).or(base.where(privacy: false)).to_sql
end
恷K議にMまれる SQL
WITH users AS (
SELECT "users"."id", "users"."name", "users"."created_at", "users"."updated_at"
FROM "users" WHERE ("users"."id" = 10 OR "users"."privacy" = 'f'))
, t AS (SELECT id, name FROM users) -- <- ここに秘ってるのかリクエストされた SQL
SELECT JSON_AGG(t) AS result FROM t
SQL インジェクションで棒
ぬのでは
SELECT 1), killer AS (DELETE FROM likes CASCADE RETURNING *
みたいな、吭あるい栽わせをさ
れたらどうするのか
SQL インジェクションで棒
ぬのでは
_かに、likes が畠しされる
SQL になってしまう
WITH users AS (
SELECT "users"."id", "users"."name", "users"."created_at", "users"."updated_at"
FROM "users" WHERE ("users"."id" = 10 OR "users"."privacy" = 'f'))
, t AS (SELECT 1), killer AS (DELETE FROM likes CASCADE RETURNING *)
SELECT JSON_AGG(t) AS result FROM t
SQL インジェクションで棒
ぬのでは
送墳に、匯指 SQL パ`サ`に个
せる駅勣がある
PgQuery.parse("SELECT 1), killer AS (DELETE FROM likes CASCADE RETURNING *")
#=> PgQuery::ParseError: syntax error at or near ")" (scan.l:1121)
SQL インジェクションで棒
ぬのでは
でもまぁ、いくら SQL として
valid でも、噸宥に DELETE FROM
likes とか僕られてくるかもしれな
い
猟直をて、険恬喘のある猟が根
まれていないかどうかをチェックし
て返する駅勣がある
sql_ast = PgQuery.parse('DELETE FROM users')
mutate_stmts = %w[TruncateStmt DeleteStmt UpdateStmt InsertStmt]
sql_ast.tree.first.dig("RawStmt","stmt").keys & mutate_stmts
#=> ["DeleteStmt"]
pg_query
pg_query 宴旋
p PgQuery.parse("select id, name from users")
#=> #<PgQuery:0x00007f98a61374a0
# @aliases=nil,
# @cte_names=nil,
# @query="select id, name from users",
# @tables=nil,
# @tree=
# [{"RawStmt"=>
# {"stmt"=>
# {"SelectStmt"=>
# {"targetList"=>
# [{"ResTarget"=>
# {"val"=>{"ColumnRef"=>{"fields"=>[{"String"=>{"str"=>"id"}}], "location"=>7}}, "location"=>7}},
# {"ResTarget"=>
# {"val"=>{"ColumnRef"=>{"fields"=>[{"String"=>{"str"=>"name"}}], "location"=>11}}, "location"=>11}}],
# "fromClause"=>[{"RangeVar"=>{"relname"=>"users", "inh"=>true, "relpersistence"=>"p", "location"=>21}}],
# "op"=>0}}}}],
# @warnings=[]>
}方 DB
Rails 6.0 から、replica 奉來のサ
ブのコネクションのO協がg
にけるようになった
development:
primary:
<<: *default
database: sqlql_development
readonly:
<<: *default
database: sqlql_development
replica: true
replica 奉來のコネクション
SQLQL のI尖をするときだけ
replica 奉來のコネクションを聞
えば、Mutations っぽい SQL は
Rails が、い討れて宴旋っぽい
ActiveRecord::Base.connected_to(database: :readonly) do
User.first.update(name: 'hoge')
end
#=> ActiveRecord::ReadOnlyError
#=> (Write query attempted while in readonly mode...
WITH は裡ないらしい
CTE の WITH 鞘は Rails 議には
ホワイトリストに秘ってないっ
ぽい´´
なぜ WITH がホワイトでないかにつ
いてはLくなるので護曚靴泙坑
になる繁はいて和さい
ActiveRecord::Base.connected_to(database: :readonly) do
ActiveRecord::Base.connection.execute(
"WITH t AS (SELECT 1 AS n) SELECT * FROM t"
)
end
#=> ActiveRecord::ReadOnlyError
#=> (Write query attempted while in readonly mode...
DB ユ`ザ`の慙
せっかく}方 DB C嬬があるん
だから、云輝に READONLY な
ユ`ザ`を恬って聞えばよい
create user readonlyuser with password 'readonlyuser' NOCREATEDB NOCREATEROLE;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "readonlyuser";
DB ユ`ザ`の慙
Rails 6 宴旋
development:
primary:
<<: *default
database: sqlql_development
readonly:
<<: *default
database: sqlql_development
replica: true
username: readonlyuser
password: readonlyuser
SQLQL の巌樋來
Generated Record Bomb
SELECT generate_series(1, 100000000) AS death
Recurring Nightmare
WITH RECURSIVE r AS (
SELECT 1 AS n UNION ALL SELECT n + 1 AS n FROM r)
SELECT * FROM r
SQLQL の巌樋來
Public Schema
SELECT * FROM public.users
Information Table
SELECT * FROM pg_user
SQLQL の巌樋來
まだまだg表巌樋來があるはずな
ので、採か櫃鼎い燭藹未┐討だ
さい
せるサンプルアプリケ`ション
があります
Powered by Rabbit 2.2.2 and COZMIXNG

More Related Content

SQLQL とは。