2016-07-29 29 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的截图吗? –