Search code examples
mysqldelphidelphi-xe7firedac

Why am I getting list index out of bounds (1) error?


I am getting this error message:

List index out of bounds (1)

when trying to select information from my database. I am using Delphi XE7, MySQL 6.2, FDConnection and FDQuery. My code is:

Procedure TAppointmentForm.GetTreatPrice;
Begin
  TreatPriceQuery.SQL.Text:= 'Select Cost from Treatment where TreatName = '+quotedstr(Treatment)+'';
  TreatPriceQuery.Open;
  TreatPrice:= TreatPriceQuery.FieldByName('Cost').AsInteger;
End;

I am using a CheckBoxList to get Treatment. My code for this is:

Procedure TAppointmentForm.GetAppCost;
Var
  Count: Integer;
begin
  for Count := 0 to (Count1-1) do
    Begin
      if TreatmentCheckListBox.State[Count] = cbChecked then
        Begin
          Treatment:= TreatmentCheckListBox.Items.Strings[Count];
          GetTreatPrice;
          AppCost:= AppCost + TreatPrice;
        End
      Else
        AppCost:= AppCost;
    End;
end;

Solution

  • Your code is overly complex. You can use the Checked property of the TCheckListBox, and drop the Strings totally when accessing the items in the content (Strings is the default property of Items). Also, you should use the Count of Items in your loop.

    Procedure TAppointmentForm.GetAppCost;
    Var
      Idx: Integer;
    begin
      for Idx := 0 to TreatmentCheckListBox.Items.Count - 1 do
      Begin
        if TreatmentCheckListBox.Checked[Idx] then
        Begin
          Treatment:= TreatmentCheckListBox.Items[Idx];
          GetTreatPrice;
          AppCost:= AppCost + TreatPrice;
        End;
      // The next two lines are a non operation. Assigning a
      // variable to itself does nothing. Remove them entirely
     // Else
     //  AppCost:= AppCost;
        End;
    end;
    

    Also, stop concatenating text for your SQL, and use parameterized queries instead, both for efficiency and for protection against SQL injection.

    Procedure TAppointmentForm.GetTreatPrice;
    Begin
      TreatPriceQuery.SQL.Text:= 'Select Cost from Treatment where TreatName = :TreatName';
      TreatPriceQuery.ParamByName('TreatName').AsString := Treatment;
      TreatPriceQuery.Open;
      TreatPrice:= TreatPriceQuery.FieldByName('Cost').AsInteger;
    End;
    

    I agree with @Remy's content in the comment to your question, as well. You should be passing parameters around instead of using global variables.

    function TAppointmentForm.GetTreatPrice(const TreatmentName: String): Integer;
    Begin
      TreatPriceQuery.SQL.Text:= 'Select Cost from Treatment where TreatName = :TreatName';
      TreatPriceQuery.ParamByName('TreatName').AsString := TreatmentName;
      TreatPriceQuery.Open;
      Result := TreatPriceQuery.FieldByName('Cost').AsInteger;
    End;
    
    Procedure TAppointmentForm.GetAppCost;
    Var
      Idx: Integer;
    begin
      AppCost := 0;
      for Idx := 0 to TreatmentCheckListBox.Items.Count - 1 do
      Begin
        if TreatmentCheckListBox.Checked[Idx] then
        Begin
          AppCost := AppCost + GetTreatPrice(TreatmentCheckListBox.Items[Idx]);
        End;
      End;
    end;