0

there. I am trying to search for a string contained in any column of a sql table by adding all the Fieldnames to the WHERE clause using a for loop. Also I use parameters to protect against SQL injection. But when I run I get an error like this:

Unspecified error

How can this be fixed and what is the problem (Not necessarily in that order). Here is my code. I am running Delphi 7

procedure TfrmView.edtSearchChange(Sender: TObject);
var
  i, i2: integer;
  obj: TEdit;
  QueryText: string;
begin
  obj:= Sender as TEdit;

  with dmInfo do
    begin
      qryInfo.SQL.Clear;
      qryInfo.SQL.Add('SELECT * FROM ' + tableName);
      qryInfo.Open;

      tblInfo.SQL.Clear;
      tblInfo.SQL.Add('SELECT * FROM ' + tableName);
      tblInfo.SQL.Add('WHERE (' + qryInfo.Fields[0].FieldName + ' LIKE :SQuery0)');
      QueryText:= '%' + obj.Text + '%';
      tblInfo.Parameters.ParamByName('SQuery0').Value:= QueryText;
      ShowMessage(QueryText);
      ShowMessage(tblInfo.Parameters.ParamByName('SQuery0').Value);
      for i:= 1 to qryInfo.FieldCount - 1 do
        begin
          tblInfo.SQL.Add(' OR (' + qryInfo.Fields[i].FieldName + ' LIKE :SQuery' + IntToStr(i) + ')');
          tblInfo.Parameters.ParamByName('SQuery' + IntToStr(i)).Value:= '%' + obj.Text + '%';
        end;
    tblInfo.Open;
end;
Simon Erasmus
  • 134
  • 12
  • You've confused `Field.FieldName` and `Field.Value` again. When setting parameter values, you want to use the field's **content**, not the field's **name**. You really should learn to actually read the code you're writing. – Ken White Aug 14 '16 at 20:49
  • Sorry I pasted wrong code. Was gonna write the question yesterday but only wrote it today. I edited the question's code. Same error as before @KenWhite – Simon Erasmus Aug 14 '16 at 20:57
  • Place a TMemo on your form and, before you call tblInfo.Open, copy tblInfo.Sql.Text into it. I suspect you will see your error. – MartynA Aug 14 '16 at 21:35
  • Move your ShowMessage down to just above your `tblInfo.Open`. (We just went through this Friday, didn't we?) – Ken White Aug 14 '16 at 21:36
  • Ok I did that. Everything looks normal, but should the output look like this: SELECT * FROM tblGymnast WHERE (GymnastID LIKE :SQuery0) OR (Surname LIKE :SQuery1) OR ..... Goes on like that. Should SQuery be displayed and not the value it is holding? – Simon Erasmus Aug 14 '16 at 21:50
  • Yes, that's correct. The replacement is done when the query is executed. – Ken White Aug 14 '16 at 21:53
  • Ok but still giving error tho. What do I do? – Simon Erasmus Aug 14 '16 at 21:54
  • 1
    If I remember correctly, not all of the columns you're querying are text (you have some numeric columns). You can't use `LIKE` on any data type but text (CHAR/VARCHAR). – Ken White Aug 14 '16 at 21:56
  • No, all my columns are text, I changed it all to text. – Simon Erasmus Aug 14 '16 at 21:59
  • You changed your database to make all of the table columns text? – Ken White Aug 14 '16 at 22:34
  • Do you perhaps need a space before `WHERE`? – 500 - Internal Server Error Aug 14 '16 at 22:47
  • 2
    @500-InternalServerError: No. Using SQL.Add adds a CR at the end of the line, so there's no missing space. – Ken White Aug 14 '16 at 22:59
  • Ah, thanks, Ken - news to me. – 500 - Internal Server Error Aug 14 '16 at 23:20
  • @500-InternalServerError `SQL` is just a `TStrings` property. `TStrings.Add` has always added a line break. One of the main purposes of it. I'm rather surprised a developer with such experience would not know this. – Jerry Dodge Aug 15 '16 at 00:01
  • What you're doing is extremely atypical. (Certainly changing all columns to char/varchar just so you can do this dodgy search is an ill-conceived hack!) Ordinarily, when binding parameters of a query, you know in advance how many parameters there are. So you can try making your code flow a little more "conventional": First add up your parameters (_without setting any values_); and only when all have been added, then set all the values. – Disillusioned Aug 15 '16 at 00:33
  • I would try to first build the entire SQL statement and only then assign parameters values (I do not have Delphi now, so I can't check). also to get filed names of the table you could use SCHEMA information from the connection object or at-least use `SELECT * FROM mytable WHERE 1=0` so it wont fetch ALL records just to know the table fields, – kobik Aug 15 '16 at 08:22
  • Also, You must use LIKE only with text type columns as @Ken wrote. so you need to check the field data type in the loop when you construct the SQL and parameters values. – kobik Aug 15 '16 at 08:26
  • If you want us to help you, please [edit] your post to provide the DDL (CREATE TABLE) statement, some sample data for that table, and include a tag for the DBMS (database) you're using. This speculating about what you might or might not have done or what you can *try* to see if it works us useless. Provide the details we need to help, by making an [edit] to the question to do so, instead of posting in comments.. – Ken White Aug 15 '16 at 12:39

1 Answers1

-1

The whole code makes no sense.

  • You let the code run every time you change a letter. run by an onChange event
  • five input/letter to the edtSearch input field means the code is executed five times without interruption immediately
  • If you delete all content in the edtSearch input field at once, which is also a change event. This time it runs with an empty edtSearch.text
  • How can you expect that this works without exceptions
  • You open each time two tables without to close them before.
  • you are using a variable, which suggests that this event is also connected to other TEdits.

    obj: TEdit;
    obj:= Sender as TEdit;

  • You clear the SQL on an open table.

  • you have two tables the first one does nothing more than SQL.clear and open
  • You're using fields from first table and create the SQL for second table
  • Even if both tables are the same, it makes no sense to use the fields from the first table.
    It is confusing, misleading and unnecessary.

First of all remove the code out of the onChange event

What you want to do with this code
to search for values on all fields from the tblInfo can be done without the first tabel qryInfo

you do not need to increment the params.

Do not create the params all the time from SQuery1 to maybe SQuery100

if you only use one param (the search value is always the same)
You can set all params with a single use tblInfo.Parameters.ParamByName() before the tblInfo.Open
but NOT in the loop.

This will replace all params :SQuery all at once with the value

SQL.Text :

SELECT * FROM tableName
WHERE (IDmember LIKE :SQuery)
OR (memberName LIKE :SQuery)
OR (petName LIKE :SQuery)
OR (Address LIKE :SQuery)

Maximum Length Of An SQL Statement

Is different from database to database

How many OR clauses can I use in a single WHERE condition in MySql query?

I know there was a limit in the past. But now the experts knowledge is different

only one of the opinions

The truth is that it's limited to the resources available on the database, the size of the data set in question, the indexes being addressed (or lack thereof) and the complexity of each clause.

If your goal is to find a person record that meets multiple criteria, I am willing to bet you won't run in to a limit. You could easy OR condition with 20 to 30 conditions and no user is going to provide more that that / person records won't have more than one that meets that many conditions.

moskito-x
  • 11,832
  • 5
  • 47
  • 60
  • Do you understand how the `Parameters` object works? – Disillusioned Aug 15 '16 at 06:06
  • I know it's not working right at **any position** in the query. Also using a quoted value on a (int) field. I also found out you can not place **:xyzParam** at any place in a query. In the past I have much problems until I found out I can use params most like `WHERE member_name = :xyzparam` thats a good place . – moskito-x Aug 15 '16 at 06:16
  • DV removed. This answer is now helpful and more relevant. If OP implements your suggestions, it will certainly be an improvement; though it's unclear whether this will fix his specific problem. – Disillusioned Aug 15 '16 at 23:40