The problem is, that every time your method is executed, you're adding a SQL statement into your query. If you inspect while debugging for its value, or just ShowMessage(UserQuery.SQL.Text) you'll clearly see it
It will look like this:
Select Password as Password1 from Users where Username = :Username
Select Password as Password1 from Users where Username = :Username
Select Password as Password1 from Users where Username = :Username
...
The query then fails because from the second to the last :Username parameter, no value is provided
There are a few ways to fix it. One of the may involve Clearing the Query then assign the SQL statement again:
UserQuery.Clear; // clear the query before adding the SQL statement
UserQuery.SQL.Add('Select Password as Password1 from Users where Username = :Username');
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;
Or you can just assign directly to the Text property which will replace the whole string with the new supplied value:
UserQuery.SQL.Text := 'Select Password as Password1 from Users where Username = :Username';
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;
Since you are using the same query over and over, the most ideal setup would be initialize it (on a constructor for example) and leave it on a Prepared state. A prepared SQL statement is preparsed and sent to the DB engine, leaving it ready to execute. It should be used when you have a query or command that you need to execute over and over and the only thing you change are the parameters values (just your case)
procedure TForm1.Create(Sender: TObject);
begin
UserQuery.SQL.Text := 'Select Password as Password1 from Users where Username = :Username';
// it's a good practice to set the parameter type
UserQuery.Parameters.ParamByName('Username').DataType := ftString;
// prepares the query: preparses sql, sends it to the DB engine, etc
UserQuery.Prepared := True;
end;
// usage
procedure TForm1.YourLoginMethod;
begin
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;
try
sPassword := UserQuery.FieldByName('Password1').AsString;
// perform login logic
finally
UserQuery.Close;
end;
end;
Just a couple things more to note. I recommend that, similar to set a parameters DataType, you use type-safe TField properties, aka .AsString, .AsInteger, etc
The default property of TDataSet will return a Variant for the given field value, and the perform an implicit conversion. I suggest being explicit since you know your data types better than the RTL
Also a try-finally block is needed here. When using prepared querys, every time you execute them, you need to have a closed query, set the parameters and then call open. The try-finally will grant that every time you open the query, it will be closed regardless of execptions that may ocurr