2016-07-29 28 views
0

我想填充字符串變量以在TQuery中使用。德爾福 - 字符串中的單引號

如何在字符串變量中獲得單引號。在下面的代碼ShowMessage COMAND顯示COMPNAME正確的,因爲「testcomp隔離」,但在sql_str值‘’testcomp隔離'?

我一直在使用QuotedStr嘗試。

+2

一個字:使用參數。不要連接SQL查詢,你很容易受到SQL注入! – whosrdaddy

+0

'ShowMessage'和'sql_str'應該產生相同的字符串(除了在每種情況下你所做的不同的間距外)。花點精力理解你自己的問題,這樣你就可以提出一個有意義的問題。並請發佈一個MCVE。 –

回答

2

你的代碼已經演示了答案通過單引號加倍逃生在一個Delphi串單引號所以這個字符串具有長度1,而單個字符是一個單引號:

'''' 

這是由文檔清楚地解釋:http://docwiki.embarcadero.com/RADStudio/en/Fundamental_Syntactic_Elements#Character_Strings

引用字符串中的兩個序列撇號表示單個字符,即撇號。

除了你問的問題之外,我必須向你推薦SQL準備好的查詢和參數。他們將刪除引用需求並避免SQL注入的可怕風險。

0

你的代碼的工作:

CompName := 'TestComp''; DROP TABLE pg_catalog.pg_students; --'; 

sql_str := 'SELECT datname FROM pg_catalog.pg_database WHERE lower(datname) = ''' + CompName + ''''; 

ShowMessage(sql_str); 

但也許我也建議你避免SQL注入通過QuotedStr

sql_str := 'SELECT datname '+#13#10+ 
      'FROM pg_catalog.pg_database'+#13#10+ 
      'WHERE lower(datname) = '+QuotedStr(CompName); 

示例使用SQL:

Connection.Execute(sql); 

假設爲例e使用參數。我不知道語法:

cmd: TADOCommand; 

cmd := TADOCommand.Create; 
cmd.Connection := Connection; 
cmd.CommandText := 'SELECT datname FROM pg_catalog.pg_database'+#13#10+ 
     'WHERE lower(datname) = %datname%'; 
cmd.AddParameter('datname', DataType_WVarChar); 
cmd.ParamByName('datname').SetString(CompName); 
cmd.Execute; 
cmd.Free; 
+2

避免SQL注入的更好方法是使用參數化查詢,而不是手動創建SQL查詢字符串。 –

+1

@RemyLebeau參數化查詢的一個缺點是,您無法看到組件發出的最終SQL。 –

+2

這裏的方法並不能避免注入 –

9

你說你嘗試使用QuotedStr(),但你表現出的代碼不使用它。它應該是這樣的:

CompName := 'TestComp'; 
sql_str := 'SELECT datname FROM pg_catalog.pg_database WHERE lower(datname) = ' + QuotedStr(CompName); 
ShowMessage(sql_str); 

話雖這麼說,你真的應該使用parameterized query,而不是手動構建SQL語句。例如:

Query1.SQL.Text := 'SELECT datname FROM pg_catalog.pg_database WHERE lower(datname) = :Name'; 
Query1.ParamByName('Name').AsString := 'TestComp'; 

使用參數化查詢有一些重大的好處:

  1. 是防止SQL注入攻擊的更安全,更有效的方式,因爲數據庫引擎驗證和格式危險值您。不要手動做!

  2. 參數化查詢允許數據庫引擎安全且一致地格式化SQL語句。這對於諸如日期/時間值之類的東西很重要,可以使用任意數量的特定於DB的本地化格式以字符串格式表示日期/時間值。這還允許您以本地數據格式(整數,斑點等)指定任何參數值,而無需手動將其轉換爲字符串。讓數據庫引擎爲您處理所有格式。

  3. 需要多次執行但不需要在執行之間更改的SQL語句,可以通過在服務器端預先準備好一次,然後按原樣執行客戶端隨時需要。每次要執行查詢時,創建新的SQL語句的速度更快,效率更高。這包括參數化查詢。由於參數化查詢的語法不改變,你可以預先做準備,然後根據需要多次使用不同的參數值執行它,例如:

    Query1.SQL.Text := 'SELECT datname FROM pg_catalog.pg_database WHERE lower(datname) = :Name'; 
    Query1.Prepare; 
    
    ... 
    
    Query1.ParamByName('Name').AsString := 'some value'; 
    Query1.Open; 
    // use result set as needed... 
    Query1.Close; 
    
    ... 
    
    Query1.ParamByName('Name').AsString := 'some other value'; 
    Query1.Open; 
    // use result set as needed... 
    Query1.Close; 
    
    ... 
    
    Query1.UnPrepare; 
    
+1

感謝關於數據庫引擎緩存準備好的sql的觀點。經常被忽視。 – DavidG

+0

@remy希望你能看到屏幕截圖。你會看到,即使使用QuotedStr,我仍然可以獲得TestComp – Gerhard

+0

@Gerhard的截圖嗎? –