DBGo INSERT INTO via SQL.CommandText - delphi

I have taken the habit to use SQL.TEXT variable to initialize my queries in order to avoid two statements: SQL.Clear; SQL.Add( ); using DBExpress.
Using dbGo for a new small project, this makes:
SQL.CommandText := 'INSERT INTO LeaveClass (id,name,color,status) VALUES (1,''Joe'',255,''Ok'')';
ExecSql;
This command breaks with a syntax error. But if we use:
SQL.Clear;
SQL.Add( 'INSERT INTO LeaveClass (id,name,color,status) VALUES (1,''Joe'',255,''Ok'')' );
ExecSql;
It works fine! Well I have wasted some time before catching up this problem and find its way around. What errors do I do? May be the dbGo.ADOQUERY.Sql.Clear makes a deep cleaning that the assignment via dbGo.ADOQUERY.SQL.CommandText doesn't. Weird. Any commands?

CommandText really only works for SELECT or other operations that return data (recordsets). It's not designed for ExecSQL or INSERT/DELETE type operations.
Simply use ADOQuery.SQL.Text instead:
ADOQuery1.SQL.Text := 'INSERT INTO LeaveClass (id,name,color,status) VALUES (1,''Joe'',255,''Ok'')';
ADOQuery1.ExecSQL;
ADOQuery1.Close;
Setting the Text property directly automatically replaces what was there before, removing the need for Clear.

Related

How to use a SQL where statement in delphi properly?

I have a problem with issuing a SQL statement. I know that the English value should be a string on its own and I've tried that but it keeps throwing me one of these errors
procedure TfrmPetersonGroup.btnEnglishClick(Sender: TObject);
var
sSqlQuery:string;
begin
//2.4
dmoBandB.qryQuery.SQL.Clear;
sSqlQuery:='DELETE FROM tblClients WHERE Nationality =' + ' English';
dmoBandB.qryQuery.SQL.Text := sSqlQuery;
dmoBandB.qryQuery.active := true;
end;
I suggest you get a safe query. As below:
procedure SafeDeleteReq(SQLQuery: TSQLQuery; del: string);
begin
SQLQuery.SQL.Text := 'DELETE FROM tblClients WHERE Nationality=:Nationality';
SQLQuery.ParamByName('Nationality').AsString := del;
SQLQuery.ExecSQL();
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SafeDeleteReq(SQLQuery1, 'English');
end;
You could change your sSql to
sSqlQuery:='DELETE FROM tblClients WHERE Nationality = ' + QuotedStr('English');
just to get it working, but that's not the best idea, see below.
Your version of it caused the error because, without quotes around it, the Sql parser thought that English was an identifier, e.g. another column name like Nationality.
Using QuotedStr around column values ensures that single-quote characters embedded in the value, like
O'Brien
are escaped correctly.
The other thing is that you should replace
dmoBandB.qryQuery.active := true;
by
dmoBandB.qryQuery.ExecSql;
The reason is that setting Active to True is equivalent to calling .Open, which is invalid in this context because .Open only works if the Sql query returns a result set and DELETE does not (sorry, I should have noticed this problem first time around). Once you've called ExecSql, you can reopen the table by setting qryQuery's Sql.Text to a valid SELECT statement and then calling .Open.
However, a betteer way to avoid your initial problem would be to get into the habit of using parameterised Sql statements - see http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_Parameters_in_Queries, which is applicable to all Sql DML statements (Insert, Delete, Update, Select, etc). Apart from anything else, this may help you avoid Sql Injection exploits (https://en.wikipedia.org/wiki/SQL_injection).

Delphi DBGrid date format for Firebird timestamp field

I display the content of a Firebird database into a TDBgrid. The database has a 'TIMESTAMP' data type field that I would like to display with date/time format:
'YYYY/MM/DD HH:mm:ss'. (Now its displayed as 'YYMMDD HHmmss')
How to achieve this?
I tried this:
procedure TDataModule1.IBQuery1AfterOpen(DataSet: TDataSet);
begin
TDateTimeField(IBQuery1.FieldByName('timestamp_')).DisplayFormat := 'YYYY/MM/DD HH:mm:ss';
end;
But this causes some side effects at other parts of the program, so its not an alternative. For example at the 'IBQuery1.Open' statement I get the '...timestamp_ not found...' debugger message in the method that I clear the database with.
function TfrmLogger.db_events_clearall: integer;
begin
result := -1;
try
with datamodule1.IBQuery1 do begin
Close;
With SQL do begin
Clear;
Add('DELETE FROM MEVENTS')
end;
if not Prepared then
Prepare;
Open; //Exception here
Close;
Result := 1;
end;
except
on E: Exception do begin
ShowMessage(E.ClassName);
ShowMessage(E.Message);
Datamodule1.IBQuery1.close;
end;
end;
end;
I get the same exception message when trying to open the query for writing into the database.
*EDIT >>
I have modified the database clear as the following:
function TfrmLogger.db_events_clearall: integer;
var
IBQuery: TIBQuery;
IBTransaction: TIBTransaction;
DataSource: TDataSource;
begin
result := -1;
//Implicit local db objects creation
IBQuery := TIBQuery.Create(nil);
IBQuery.Database := datamodule1.IBdbCLEVENTS;
DataSource := TDataSource.Create(nil);
DataSource.DataSet := IBQuery;
IBTransaction := TIBTransaction.Create(nil);
IBTransaction.DefaultDatabase := datamodule1.IBdbCLEVENTS;
IBQuery.Transaction := IBTransaction;
try
with IBQuery do begin
SQL.Text := DELETE FROM MSTEVENTS;
ExecSQL;
IBTransaction.Commit;
result := 1;
end;
except
on E : Exception do
begin
ShowMessage(E.ClassName + ^M^J + E.Message);
IBTransaction.Rollback;
end;
end;
freeandnil(IBQuery);
freeandnil(DataSource);
freeandnil(IBTransaction);
end;
After clearing the database yet i can load the records into the dbgrid, seems like the database has not been updated. After the program restart i can see all the records been deleted.
The whole function TfrmLogger.db_events_clearall seems very dubious.
You do not provide SQL_DELETE_ROW but by the answer this does not seem to be SELECT-request returning the "resultset". So most probably it should NOT be run by ".Open" but instead by ".Execute" or ".ExecSQL" or something like that.
UPD. it was added SQL_DELETE_ROW = 'DELETE FROM MEVENTS'; confirming my prior and further expectations. Almost. The constant name suggests you want to delete ONE ROW, and the query text says you delete ALL ROWS, which is correct I wonder?..
Additionally, since there is no "resultset" - there is nothing to .Close after .Exec.... - but you may check the .RowsAffected if there is such a property in DBX, to see how many rows were actually scheduled to be deleted.
Additionally, no, this function DOES NOT delete rows, it only schedules them to be deleted. When dealing with SQL you do have to invest time and effort into learning about TRANSACTIONS, otherwise you would soon get drown in side-effects.
In particular, here you have to COMMIT the deleting transaction. For that you either have to explicitly create, start and bind to the IBQuery a transaction, or to find out which transaction was implicitly used by IBQuery1 and .Commit; it. And .Rollback it on exceptions.
Yes, boring, and all that. And you may hope for IBX to be smart-enough to do commits for you once in a while. But without isolating data changes by transactions you would be bound to hardly reproducible "side effects" coming from all kinds of "race conditions".
Example
FieldDefs.Clear; // frankly, I do not quite recall if IBX has those, but probably it does.
Fields.Clear; // forget the customizations to the fields, and the fields as well
Open; // Make no Exception here
Close;
Halt; // << insert this line
Result := 1;
Try this, and I bet your table would not get cleared despite the query was "opened" and "closed" without error.
The whole With SQL do begin monster can be replaced with the one-liner SQL.Text := SQL_DELETE_ROW;. Learn what TStrings class is in Delphi - it is used in very many places of Delphi libraries so it would save you much time to know this class services and features.
There is no point to Prepare a one-time query, that you execute and forget. Preparation is done to the queries where you DO NOT CHANGE the SQL.Text but only change PARAMETERS and then re-open the query with THE SAME TEXT but different values.
Okay, sometimes I do use(misuse?) explicit preparation to make sure the library fetches parameters datatypes from the server. But in your example there is neither. Your code however does not use parameters and you do not use many opens with the same neverchanging SQL.text. Thus, it becomes a noise, making longer to type and harder to read.
Try ShowMessage(E.ClassName + ^M^J + E.Message) or just Application.ShowException(E) - no point to make TWO stopping modal windows instead of one.
Datamodule1.IBQuery1.close; - this is actually a place for rolling back the transaction, rather than merely closing queries, which were not open anyway.
Now, the very idea to make TWO (or more?) SQL requests going throw ONE Delphi query object is questionable per se. You make customization to the query, such as fixing DisplayFormat or setting fields' event handlers, then that query is quite worth to be left persistently customized. You may even set DisplayFormat in design-time, why not.
There is little point in jockeying on one single TIBQuery object - have as many as you need. As of now you have to pervasively and accurately reason WHICH text is inside the IBQuery1 in every function of you program.
That again creates the potential for future side effects. Imagine you have some place where you do function1; function2; and later you would decide you need to swap them and do function2; function1;. Can you do it? But what if function2 changes the IBQuery1.SQL.Text and function1 is depending on the prior text? What then?
So, basically, sort your queries. There should be those queries that do live across the function calls, and then they better to have a dedicated query object and not get overused with different queries. And there should be "one time" queries that only are used inside one function and never outside it, like the SQL_DELETE_ROW - those queries you may overuse, if done with care. But still better remake those functions to make their queries as local variables, invisible to no one but themselves.
PS. Seems you've got stuck with IBX library, then I suggest you to take a look at this extension http://www.loginovprojects.ru/download.php?getfilename=uploads/other/ibxfbutils.zip
Among other things it provides for generic insert/delete functions, which would create and delete temporary query objects inside, so you would not have to think about it.
Transactions management is still on you to keep in mind and control.

Delphi - Why am I getting this Access Violation? Is there a limit to ADOQuery parameteres?

I have this code that is returning an Access Violation ('Access violation at address 74417E44 in module 'sqloledb.dll'. Read of address 786E3552') and I can't identify where is the problem. My only guess is that ADOQuery has a limit for the number of parameters we can pass.
The code is as follows:
With qryInsert do
begin
Active := False;
Close;
Sql.Clear;
Sql.Add('Insert Into MyTable(ColumnOne, ');
Sql.Add(' ColumnTwo, ');
Sql.Add(' ColumnThree, ');
Sql.Add(' ColumnFour, ');
Sql.Add(' ColumnFive, ');
Sql.Add(' ColumnSix, ');
Sql.Add(' ColumnSeven, ');
Sql.Add(' ColumnEight, ');
Sql.Add(' ColumnNine, ');
Sql.Add(' ColumnTen, ');
Sql.Add(' ColumnEleven, ');
Sql.Add(' ColumnTwelve, ');
if qrySelect.FieldByName('ColumnTwelve').AsSTring = 'Y' then
begin
Sql.Add(' ColumnThirteen, ');
Sql.Add(' ColumnFourteen, ');
Sql.Add(' ColumnFifteen, ');
end;
Sql.Add(' ColumnSixteen, ');
if qrySelect.FieldByName('ColumnSixteen').AsSTring = 'Y' then
begin
Sql.Add(' ColumnSeventeen, ');
Sql.Add(' ColumnEighteen, ');
Sql.Add(' ColumnNineteen, ');
end;
if qrySelect.FieldByName('ColumnTwenty').AsSTring = 'Y' then
begin
Sql.Add(' ColumnTwenty, ');
Sql.Add(' ColumnTwentyOne, ');
Sql.Add(' ColumnTwentyTwo, ');
Sql.Add(' ColumnTwentyThree, ');
end
else
Sql.Add(' ColumnTwenty, ');
Sql.Add(' ColumnTwentyFour) ');
Sql.Add('Values(:ColumnOne, :ColumnTwo, :ColumnThree, :ColumnFour, ');
Sql.Add(' :ColumnFive, ' + dateDB + ', :ColumnSeven, ');
Sql.Add(' :ColumnEight, :ColumnNine, :ColumnTen, ');
Sql.Add(' :ColumnEleven, ');
Sql.Add(' :ColumnTwelve, ');
if qrySelect.FieldByName('ColumnTwelve').AsSTring = 'Y' then
Sql.Add(' :ColumnThirteen, :ColumnFourteen, :ColumnFifteen, ');
Sql.Add(' :ColumnSixteen, ');
if qrySelect.FieldByName('ColumnSixteen').AsSTring = 'Y' then
Sql.Add(' :ColumnSeventeen, :ColumnEighteen, :ColumnNineteen, ');
if qrySelect.FieldByName('ColumnTwenty').AsSTring = 'S' then
begin
Sql.Add(' :ColumnTwenty, ');
Sql.Add(' :ColumnTwentyOne, :ColumnTwentyTwo, :ColumnTwentyThree, ');
end
else
Sql.Add(' :ColumnTwenty, ');
Sql.Add(' :ColumnTwentyFour) ');
{And then for all the parameteres, pass the value}
Parameters.ParamByName('ColumnOne').Value := varColumnOne;
...
Parameters.ParamByName('ColumnTwentyFour').Value := varColumnTwentyFour;
ExecSQL;
end;
I get the error on this line:
Sql.Add(' :ColumnTwelve, ');
which is the 11th parameter in my insert statement.
If I comment this line I get the error in the next parameter.
If I put the value directly like this:
Sql.Add(' ' + varColumnTwelve + ', ');
It works fine, but I get the error in the next parameter.
So it makes me wonder: does ADOQuery has a limit of how many parameters it can handle? Or if this isn't the real issue, does anyone has a clue of how I can fix this?
Notes:
I'm using Delphi 7 and Windows 8.1.
The AV only (and always) appears when debugging, it does never appear if I execute the application directly through its ".exe".
If I keep pressing "Run" after the error appears, it shows more and more AVs (I think that the number of AVs is the same as the number of parameteres that are added after the 10th), until the application continues running normally.
The insert works after all the AVs appeared on the screen. I just want to understand why am I getting this error when everything looks fine.
Changing the SQL property of a TADOQuery causes the TADOQuery to respond to that change, re-applying the modified SQL to the internal ADO component objects as well as re-parsing the SQL to identify any parameters.
For this reason, it is not advisable to modify SQL incrementally in this way. Quite apart from anything else, it is highly inefficient to have the SQL applied and parsed over and over again, before it is completely assembled.
In this case, by the time you get to the point of adding your 11th parameter, the SQL has been applied and parsed 28 times!
The fact that the AV that then results is occurring within SQLOLEDB.DLL suggests that whatever problem is occurring is a result of the changes to the SQL being applied to the internal ADO objects rather than in the VCL processing to identify parameters etc. As such, there is not much you are going to be able to do to fix the problem. The best you can do is avoid it.
You can eliminate some of this processing by setting ParamCheck := FALSE whilst modifying the SQL. This will prevent the VCL from attempting to re-parse the modified SQL to identify parameters. However, it will not prevent the SQL from being re-applied to the underlying ADO components in response to each change.
As a diagnostic exercise you could try setting ParamCheck := FALSE while modifying your SQL. When done, call the Parameters.Refresh method to ensure that the parameters collection is updated to reflect the finished SQL:
qryInsert.ParamCheck := FALSE;
qryInsert.SQL.Add(..);
qryInsert.SQL.Add(..);
qryInsert.SQL.Add(..);
qryInsert.SQL.Add(..);
qryInsert.Parameters.Refresh;
NOTE: With ParamCheck set to FALSE, you must call Parameters.Refresh before attempting to set any parameter values, otherwise the parameters won't yet exist in the Parameters collection!
If the AV still occurs after this change then this even more strongly indicates some issue with the internal ADO components not behaving well in response to repeated changes to the SQL, perhaps due to a failure to properly deal with incomplete (syntactically incorrect) SQL.
However, you can avoid triggering the change mechanism entirely by one of two ways.
Perhaps the simplest is to use BeginUpdate/EndUpdate on the TADOQuery SQL stringlist around your code that builds the SQL:
qryInsert.SQL.BeginUpdate;
try
qryInsert.SQL.Add(..);
qryInsert.SQL.Add(..);
qryInsert.SQL.Add(..);
finally
qryInsert.SQL.EndUpdate;
end;
This has the effect of suppressing the internal OnChange event inside the ADO query object until the call to EndUpdate, at which point the SQL will be applied to the internal ADO objects and the Parameters of the query object updated.
Alternatively you could assemble your SQL in an entirely separate string list, and then apply that to the TADOQuery SQL property as a single, direct change to the SQL.Text property:
sql := TStringList.Create;
try
sql.Add(..);
sql.Add(..);
sql.Add(..);
sql.Add(..);
sql.Add(..);
sql.Add(..);
qryInsert.SQL.Text := sql.Text;
finally
sql.Free;
end;
Either way, the result will be that the VCL will parse for parameters and the internal ADO objects will be updated only once, with a complete and (hopefully) syntactically correct SQL statement.
This second approach can involve a little less "boilerplate" - the try..finally here is purely to manage the temporary stringlist. If you were re-using an object in wider scope for this purpose, or using a SQL builder helper class which yields a simple string (as I do) then there is no need for this particular try..finally, making this a little more convenient and cleaner to apply:
SQLBuilder.Insert('MyTable');
SQLBuilder.AddColumn('ColumnOne');
SQLBuilder.AddColumn('ColumnTwo');
qryInsert.SQL.Text := SQLBuilder.SQL;
// qryInsert.SQL == INSERT INTO MyTable (ColumnOne, ColumnTwo)
// VALUES (:ColumnOne, :ColumnTwo)
For example.
String vs TStringList
If your preferred technique for building the SQL yields a stringlist rather than a simple string, you may be tempted to assign the stringlist directly:
qryInsert.SQL := sql;
But note that this performs an Assign() of the sql stringlist, effectively performing a 'deep copy'. You still need to ensure the stringlist assigned (sql in the above code) is freed appropriately.
Note also that this is also less efficient since it also copies other properties of the stringlist, including any objects associated with each string in the list. In this case where you are only interested in copying across the Text content of the stringlist there is no need to incur that (slight) and unnecessary overhead.
The AV only (and always) appears when debugging, it does never appear if I execute the application directly through its ".exe".
....
The insert works after all the AVs appeared on the screen. I just want to understand why am I getting this error when everything looks fine.
The access violation is raised in an external module, implemented in a language other than Delphi. Most likely the external code is behaving correctly and as designed, and the access violation is expected.
That may sound very odd but the external code clearly handles the exception since control does not pass to your code's exception handlers. As you observe, the program works correctly.
This is what is known as a first chance exception. The debugger is notified and breaks. But then control returns to the program and in this case the program deals with the exception and continues. And it is perfectly normal, albeit perhaps counter-intuitive, for code to raise a first chance access violation exception, but still be functioning correctly. As evidence for that claim, see this from an article written by a member of the VS development team:
Why the VS Debugger does not stop on first chance Access Violations (by default)?
....
The reason the default for first-chance AVs does not stop is that
sometimes Windows calls will AV, and then catch the exception
themselves and carry on happily. If we did default to stopping on
first chance AVs we would stop users in some strange place in say
kernel32.dll and many would be very confused.
So in terms of correctness, I don't think there's anything to worry about. But it does make debugging difficult. Try the various suggestions made by #Deltics. If by making those changes you happen to avoid the exception, that's all to the good. Otherwise you may need to, at least temporarily, suppress the debugger from breaking on exceptions.
If qrySelect has no 'ColumnTwelve' then
if qrySelect.FieldByName('ColumnTwelve').AsSTring = 'Y' then
will raise an exception because the FieldByName will return nil

I have a syntax error in my insert into statement

I'm using a MS Access database, with the following columns in the Admins table:
Column Type
====== ====
Name Text
Surname Text
Dateadded Date/time
Adminnumber Number(long integer)
Password Text
ID type Autonumber (Not sure if ID is relevant)
This is my code but it keeps giving me a syntax error.
ADOquery1.Active := false;
adoquery1.sql.Text := 'insert into Admins(Name, surname, Adminnumber, Dateadded,password)Values('''+edit11.Text+''', '''+edit12.text+''', '''+edit13.Text+''', '''+edit14.Text+''', '''+edit15.text+''')';
ADOquery1.ExecSQL;
Adoquery1.SQL.Text := 'select * from Admins';
ADOquery1.Active := true;
i have been trying for a day to figure it out but its the same error no matter what code i use. The error is
Project project1.exe raised exception class eoleException
with message 'Syntax error in INSERT INTO statement'.
i have also tried:
ADOquery1.SQL.Add('Insert into admins');
ADOquery1.SQL.Add('(Name , Surname, Dateadded, Adminnumber, Password)');
ADOquery1.SQL.Add('Values :Name, :Surname, :Dateadded, :adminnumber :Password)');
ADOquery1.Parameters.ParamByName('Name').Value := edit11.Text;
ADOquery1.Parameters.ParamByName('Surname').Value := edit12.Text;
ADOquery1.Parameters.ParamByName('Dateadded').Value := edit13.Text;
ADOquery1.Parameters.ParamByName('Password').Value := edit14.Text;
ADOquery1.Parameters.ParamByName('Adminnumber').Value := edit15.Text;
ADOquery1.ExecSQL;
ADOquery1.SQL.Text := 'Select * from admins';
ADOquery1.Open ;
But this code gives me a problem with the from clause
The problem is that Name (and possibly Password) is a reserved word in MS Access. It's a poor choice for a column name, but if you must use it you should escape it by enclosing it in square brackets ([]). You're also missing an opening parenthesis (() after your VALUES statement, and a comma after the :adminnumber parameter.
ADOquery1.SQL.Add('Insert into admins');
ADOquery1.SQL.Add('([Name] , [Surname], [Dateadded], [Adminnumber], [Password])');
ADOquery1.SQL.Add('Values (:Name, :Surname, :Dateadded, :adminnumber, :Password)');
ADOquery1.Parameters.ParamByName('Name').Value := edit11.Text;
ADOquery1.Parameters.ParamByName('Surname').Value := edit12.Text;
ADOquery1.Parameters.ParamByName('Dateadded').Value := edit13.Text;
ADOquery1.Parameters.ParamByName('Password').Value := edit14.Text;
ADOquery1.Parameters.ParamByName('Adminnumber').Value := edit15.Text;
ADOquery1.ExecSQL;
ADOquery1.SQL.Text := 'Select * from admins';
ADOquery1.Open;
(The error can't be moving around, as you say in the comments to your question. The only line that can possibly cause the problem is the ADOQuery1.ExecSQL; line, as it's the only one that executes the INSERT statement. It's impossible for any other line to raise the exception.)
You should make some changes here that are pretty important to the maintainability of your code.
First, break the habit immediately of using the default names for controls, especially those you need to access from your code later. You change the name by changing the Name property for the control in the Object Inspector.
It's much easier in the code to use NameEdit.Text than it is to use Edit1.Text, especially by the time you get to Edit14. It would be much clearer if Edit14 was named PasswordEdit instead, and you'll be happy you did six months from now when you have to change the code.
Second, you should avoid using the default variant conversion from string that happens when you use ParamByName().Value. It works fine when you're assigning to a text column, but isn't really good when the type isn't text (such as when using dates or numbers). In those cases, you should convert to the proper data type before doing the assignment, so that you're sure it's done correctly.
ADOQuery1.ParamByName('DateAdded').Value := StrToDate(DateEdit.Text);
ADOQuery1.ParamByName('AdminNumber').Value := StrToInt(AdminNum.Text);
Finally, you should never, ever use string concatenation such as 'SOME SQL ''' + Edit1.Text + ''','''. This can lead to a severe security issue called SQL injection that can allow a malicious user to delete your data, drop tables, or reset user ids and passwords and giving them free access to your data. A Google search will find tons of information about the vulnerabilities that it can create. You shouldn't even do it in code you think is safe, because things can change in the future or you can get a disgruntled employee who decides to cause problems on the way out.
As an example, if a user decides to put John';DROP TABLE Admins; into edit14 in your application, and you call ExecSQL with that SQL, you will no longer have an Admins table. What happens if they instead use John';UPDATE Admins SET PASSWORD = NULL; instead? You now have no password for any of your admin users.

Delphi / ADO : how to get result of Execute()?

I have declared AdoConnection : TADOConnection; and successfully connected to the default "mysql" database (so, no need to pass that code).
Now, taking baby steps to learn, I would like to AdoConnection.Execute('SHOW DATABASES', cmdText); which seems to work ok, in the sense that it doesn't throw an exception, but I am such a n00b that I don't know how I can examine the result of the command :-/
Halp!
#mawg, the SHOW DATABASES command returns an dataset with one column called 'Database', so you can use the TADOQuery component to read the data.
try this code.
var
AdoQuery : TADOQuery;
begin
AdoQuery:=TADOQuery.Create(nil);
try
AdoQuery.Connection:=AdoConnection;
AdoQuery.SQL.Add('SHOW DATABASES');
AdoQuery.Open;
while not AdoQuery.eof do
begin
Writeln(AdoQuery.FieldByname('DataBase').AsString);
AdoQuery.Next;
end;
finally
AdoQuery.Free;
end;
end;
What you need is to reach the returned _Recordset.
If you don't mind using the Delphi components, you should use TADODataSet or TADOQuery to execute a SQL command which can return any results (or the more low-evel TADOCommands' Execute methods).
If you wanty something realy simple, w/o all the VCL balast, you mignt want to try the TADOWrap class from ExplainThat (MIT licenced).
You must use an TADOQuery connected to TADODataBase. At property SQL you must include the SQl statament to retrive databases in SGDB. In SQL Server you can do this:
SELECT * FROM sysdatabases
In MySQL must exist something similar to retrieve the names.
You can connect this TADOQuery to a TDataSource and a DBGrid to see visual result or use code to explore the result of the query (some similar to this):
ADOQuery1.Open;
while not ADOQuery1.eof do begin
Name := ADOQuery1.FieldByName('DBName').AsString;
ADOQuery1.Next;
end;
Regards
You need TAdoQuery to execute statements, that return results.
If you simply want to populate a grid why dont you use adotable ?
Adotable.open;
Adotable.first;
While NOT adotable.eof do(not sure about not or <>)
Begin
Put values in variant or array;
Adotable.next;
End
Then you can let any UI access the array or variant.
Or populate a dataset.

Resources