I am thinking about adding ODBC database connectivity to an application.
The user will at runtime configure and select their database odbc connection.
Are there any components that will give me the required series of dialogs ?
Allowing the user to select the data source type, select drivers, browse already
defined ODBC connections etc.
Cheers
Sam
You can try this, if you are using ADO components.
Option 1
Uses
OleDB,
ComObj,
ActiveX;
function Edit_ADO_ODBC_ConnectionString(ParentHandle: THandle; InitialString: WideString;out NewString: string): Boolean;
var
DataInit : IDataInitialize;
DBPrompt : IDBPromptInitialize;
DataSource: IUnknown;
InitStr : PWideChar;
begin
Result := False;
DataInit := CreateComObject(CLSID_DataLinks) as IDataInitialize;
if InitialString <> '' then
DataInit.GetDataSource(nil, CLSCTX_INPROC_SERVER, PWideChar(InitialString),IUnknown, DataSource);
DBPrompt := CreateComObject(CLSID_DataLinks) as IDBPromptInitialize;
{
DBPROMPTOPTIONS_WIZARDSHEET = $1;
DBPROMPTOPTIONS_PROPERTYSHEET = $2;
DBPROMPTOPTIONS_BROWSEONLY = $8;
DBPROMPTOPTIONS_DISABLE_PROVIDER_SELECTION = $10;
}
if Succeeded(DBPrompt.PromptDataSource(nil, ParentHandle,DBPROMPTOPTIONS_PROPERTYSHEET, 0, nil, nil, IUnknown, DataSource)) then
begin
InitStr := nil;
DataInit.GetInitializationString(DataSource, True, InitStr);
NewString := InitStr;
Result := True;
end;
end;
Result:=Edit_ADO_ODBC_ConnectionString(0,OldConnectionString,NewString);
Option 2
Uses
ADODB;
PromptDataSource(Self.Handle, InitialString);
Option 3
Uses
ADODB,
AdoConEd;
procedure TMainForm.Button2Click(Sender: TObject);
Var
ADOConnection1 : TADOConnection;
begin
ADOConnection1:=TADOConnection.Create(Self);
EditConnectionString(ADOConnection1);
end;
You must Select "Microsoft OLE DB Provider for ODBC Drivers"
Bye.
PromptDataSource Function from the ADODB unit. Two parameters are
required:
the calling form's handle
a connection string . If you want no default connection string
just pass an empty string as:
var sConn : WideString;
begin
sConn := PromptDataSource(Form1.Handle, '');
end;
Related
I'm debugging Delphi code with Delphi 7 IDE, the code is not mine. My goal is to understand how this code works. This will help me to write my application which will interface with this code.
I never used Delphi in my life. I'm a C, C++, C# programmer.
I'm able to see the output (result) of the stored procedure but I need to see the content of the stored procedure (I mean the SQL statement). I looked in SQL Server side but I didn't find anything.
The stored procedure is called in this function :
function TDBDM.getID( prKeyName : string ) : integer;
begin
try
spGetSN.Parameters.ParamValues['#prKeyname'] := prKeyName;
spGetSN.open;
result := spGetSN.Fields[0].AsInteger;
finally
spGetSN.close;
end;
end;
and the stored procedure 'spGetSN' is declared here :
unit dmDB;
interface
uses
SysUtils, Classes, Forms, ADODB, DB, TypInfo, Dialogs, StdCtrls,
Controls,Registry, Windows;
type
eConnectionType = (ctSN);
TDBDM = class(TDataModule)
ADOConnectionSN: TADOConnection;
spGetSN: TADOStoredProc;
ADOQueryGetPartNoFromRMA: TADOQuery;
ADOQueryGetPartNoFromOrder: TADOQuery;
procedure ADOConnectionSNBeforeConnect(Sender: TObject);
procedure DataModuleCreate(Sender: TObject);
private
{ Private declarations }
function GetConnection( prConnectionType : eConnectionType ) :
TADOConnection;
public
{ Public declarations }
function getID( prKeyName : string ) : integer;
function getSN( prKeyName : string ) : string;
function getCommaValues( prSelect : string; prConnection :
eConnectionType = ctSN ) : string;
property pConnection[prType : eConnectionType] : TADOConnection read
GetConnection; default;
end;
var
DBDM: TDBDM;
implementation
uses dmRegistryClasses;
{$R *.dfm}
The text of the object TADOSTOREDPROC 'spGetSN' as defined in the IDE is :
object spGetSN: TADOStoredProc
Connection = ADOConnectionSN
ProcedureName = 'spGetSN;1'
Parameters = <
item
Name = '#RETURN_VALUE'
DataType = ftInteger
Direction = pdReturnValue
Precision = 10
Value = Null
end
item
Name = '#prKeyname'
Attributes = [paNullable]
DataType = ftWideString
Size = 30
Value = Null
end>
Left = 268
Top = 80
end
How can I print or watch the SQL code of this stored procedure in Delphi debugger? Thanks
The following should give you an idea how to do it:
Add a TAdoQuery called AdoQuerySP to your form and set its connection to whatever AdoConnection component you're using at the moment.
Add a TMemo to the form.
Add a TButton to the form and set its OnClick handler to execute the code below (after changing checklibuse to the name of your SP).
Code:
procedure TForm1.GetSPDefinition;
var
S : String;
begin
S := '';
AdoQuerySP.Sql.Text := 'exec sp_helptext checklibuse'; // sp_helptext
// is a Sql Server system stored proc to retrieve the definition of
// a stored proc. The definition is returned as a series of rows which need to be
// concatenated together as in the `while ...` loop below.
AdoQuerySP.Open;
while not AdoQuerySP.Eof do begin
if S <> '' then
S := #13#10 + S;
S := S + AdoQuerySP.FieldByName('Text').AsString;
AdoQuerySP.Next;
end;
// The retrieved definition is typically preceded by a number of blank lines
// which the call to Trim() remove.
Memo1.Lines.Text := Trim(S);
end;
You could query the sys.sql_modules table e.g.:
function MSSQL_GetModuleText(conn: TADOConnection; const ModuleName: WideString): WideString;
var
SQL: WideString;
rs: Variant;
begin
SQL := Format('SELECT [definition] FROM sys.sql_modules WHERE [object_id]=OBJECT_ID(N''%s'')', [ModuleName]);
rs := conn.Execute(SQL);
Result := VarToWideStr(rs.Fields[0]);
end;
Usage:
S := MSSQL_GetModuleText(ADOConnectionSN, 'dbo.spGetSN');
I need to import data from Excel into a SQL Server database. I use ADO to read the excel files.
Sometimes it happens that a row is empty in Excel, which will create an empty row import failure on the SQL Server side.
Any good idea to remove these empty rows or detect during import?
I'm looking for a rather effective code style solution, i show my current solution with the field loop here
function EmptyRow(aQuery: TADOQuery): Boolean;
var
i: Integer;
fname: string;
temp_line: string;
begin
temp_line := '';
for i := 0 to aQuery.Fields.Count - 1 do
begin
fname := aQuery.Fields[i].FieldName;
temp_line := temp_line + aQuery.FieldByName(fname).asString;
end;
if (temp_line <> '') then
result := false
else
result := true;
end;
You could exit the first thime you find a non empty string
function EmptyRow(aQuery: TADOQuery): Boolean;
var
Field: TField;
begin
for Field in aQuery.Fields do
if Field.AsString <> '' then
exit(false);
exit(True);
end;
And if you have an older Delphi you could implement it like tihs:
function EmptyRow(aQuery: TADOQuery): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to aQuery.Fields.Count - 1 do
if aQuery.Fields[I].AsString <> '' then
exit;
Result := True;
end;
I try to build REST Web Server based on mORMot framework (Delphi) and have issue with getting data from remote DB.
Server.dpr
const
CONN_STR =
'DRIVER=SQL Server Native Client 10.0;UID=user;PWD=pass;server=server;'
+ 'Trusted_Connection=No;MARS_Connection=yes';
var
Model: TSQLModel;
RESTServer: TSQLRestServerDB;
Application: TwoStreamgateApplication;
HTTPServer: TSQLHttpServer;
ODBCConnProp: TSQLDBConnectionPropertiesThreadSafe;
begin
SQLite3Log.Family.Level := LOG_VERBOSE;
SQLite3Log.Family.PerThreadLog := ptIdentifiedInOnFile;
ODBCConnProp := TODBCConnectionProperties.Create('', CONN_STR, 'wo', 'wo');
try
ODBCConnProp.ThreadingMode := tmMainConnection;
Model := CreateModel;
VirtualTableExternalRegisterAll(Model, ODBCConnProp);
try
RESTServer := TSQLRestServerDB.Create(Model, ':memory:');
try
RESTServer.DB.Synchronous := smNormal;
RESTServer.DB.LockingMode := lmExclusive;
RESTServer.CreateMissingTables;
Application := TwoStreamgateApplication.Create;
try
Application.Start(RESTServer);
HTTPServer := TSQLHttpServer.Create('8092', [RESTServer]
{$IFNDEF ONLYUSEHTTPSOCKET}, '+', useHttpApiRegisteringURI{$ENDIF});
try
HTTPServer.RootRedirectToURI('api/default');
RESTServer.RootRedirectGet := 'api/default';
writeln('"MVC WOStreamgate Server" launched on port 8092 using ',
HTTPServer.HttpServer.ClassName);
writeln(#10'You can check http://localhost:8092/api/info for information');
writeln('or point to http://localhost:8092 to access the web app.');
writeln(#10'Press [Enter] to close the server.'#10);
readln;
writeln('HTTP server shutdown...');
finally
HTTPServer.Free;
end;
finally
Application.Free;
end;
finally
RESTServer.Free;
end;
finally
Model.Free;
end;
finally
ODBCConnProp.Free;
end;
Model is described below in ServerModel.pas unit
type
TSQLBaseData = class(TSQLRecord)
private
FName: RawUTF8;
FDetailURL: RawUTF8;
FLogoURL: RawUTF8;
FDescription: RawUTF8;
published
property Name: RawUTF8 read FName write FName;
property Description: RawUTF8 read FDescription write FDescription;
property LogoURL: RawUTF8 read FLogoURL write FLogoURL;
property DetailURL: RawUTF8 read FDetailURL write FDetailURL;
end;
TSQLStation = class(TSQLBaseData)
end;
function CreateModel: TSQLModel;
implementation
function CreateModel: TSQLModel;
begin
result := TSQLModel.Create(
[TSQLStation],
'api');
end;
View model in ServerViewModel.pas unit
TServerApplication = class(TMVCApplication, IServerApplication)
public
procedure Start(aServer: TSQLRestServer); reintroduce;
procedure StationView(ID: TID; out Station: TSQLStation);
end;
implementation
procedure TServerApplication.Start(aServer: TSQLRestServer);
begin
inherited Start(aServer,TypeInfo(IServerApplication));
fMainRunner := TMVCRunOnRestServer.Create(Self).
SetCache('Default',cacheRootIfNoSession,15);
aServer.Cache.SetCache(TSQLStation);
end;
procedure TServerApplication.StationView(ID: TID; out Station: TSQLStation);
begin
RestModel.Retrieve(ID, Station);
end;
and now once I type http://localhost:8092/api/station/10 in browser, I get response
{ "errorCode":404, "errorText":"Not Found" }
in case I type http://localhost:8092/api/stationview/10 in browser I get rendered page, but without info about station=10 or any other.
Where did I make a mistake? I want simply get JSON-response to my request
UPDATE:
Another info that can help. Once I try the query
procedure TestQuery();
var
SQLDBConnection: TODBCConnection;
Q: TQuery;
begin
SQLDBConnection := TODBCConnection.Create(ODBCConnProp);
Q := TQuery.Create(SQLDBConnection);
try
Q.SQL.Clear; // optional
Q.SQL.Add('select * from dbo.Station');
Q.Open;
...
I catch an error:
Project Server.exe raised exception class EODBCException with message 'TODBCStatement - TODBCLib
error: [HY106] [Microsoft][SQL Server Native Client 10.0]Fetch type
out of range (0) '.
Solution is very simple - need to add:
Database=myDataBase;
to
CONN_STR = 'DRIVER=SQL Server Native Client 10.0;UID=user;PWD=pass;server=server;'
+ 'Trusted_Connection=No;MARS_Connection=yes';Database=myDataBase;
Thanks Arnaud for great framework!!!
I want to retrieve the SQL Server Protocols Network Configuration.
I tried searching for a windows registry or any config file related to this, but the only sample which I found is for powershell Enable or Disable a Server Network Protocol (SQL Server PowerShell), and uses .Net classes.
So the question is : How can retrieve the SQL Server Protocols Network Configuration using delphi?
You can use the ServerNetworkProtocol WMI class and also connect to the correct namespace depending of the SQL Server Version.
SQL Server 2005 = ComputerManagement
SQL Server 2008 = ComputerManagement10
SQL Server 2012 = ComputerManagement11
Try this sample
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
ComObj,
Variants;
type
TMSSQlServerType=(MSSQL2005, MSSQL2008, MSSQL2012);
procedure GetServerNetworkProtocolInfo(SQlServerType: TMSSQlServerType; const InstanceName: string);
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $00000020;
MSSQLNameSpaces : array [TMSSQlServerType] of string = ('ComputerManagement','ComputerManagement10','ComputerManagement11');
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, Format('root\Microsoft\SqlServer\%s',[MSSQLNameSpaces[SQlServerType]]), WbemUser, WbemPassword);
FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM ServerNetworkProtocol Where InstanceName="%s"', [InstanceName]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
Writeln(Format('Enabled %s',[String(FWbemObject.Enabled)]));// Boolean
Writeln(Format('MultiIpConfigurationSupport %s',[String(FWbemObject.MultiIpConfigurationSupport)]));// Boolean
Writeln(Format('ProtocolDisplayName %s',[String(FWbemObject.ProtocolDisplayName)]));// String
Writeln(Format('ProtocolName %s',[String(FWbemObject.ProtocolName)]));// String
Writeln;
FWbemObject:=Unassigned;
end;
end;
begin
try
CoInitialize(nil);
try
GetServerNetworkProtocolInfo(MSSQL2008,'MSSQLSERVER');
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
I'm having trouble inserting Unicode into a SQL Server database using Delphi ZeosLib and Delphi 7, and then reading the inserted value. I've created a simple test program that first inserts and then queries the inserted value.
The test table schema:
CREATE TABLE [dbo].[incominglog](
[message] [nvarchar](500) NULL
) ON [PRIMARY]
I've upload the simple test program source (ZeosLib source included) - click here to download. I've also included ntwdblib.dll but you can use your own.
The test program also requires TNT component which can be downloaded from here
Using the test program, the Unicode characters that I have inserted appear as question marks on retrieval - I'm not certain whether the problem lies with the insert code or the query code.
I've also tried encoding the data into utf-8 before inserting and then decoding the data after retrieving from utf-8 - please search "//inserted as utf8" in the test program source. I'm able to view the Unicode after it has been decoded, so this method works. However, for my actual application, I can't encode as UTF-8 as SQL Server doesn't support UTF-8 completely - some characters can't be stored. See my previous question here.
Will appreciate any pointers. :)
Meanwhile, here's the source for the Test program:
unit Unit1;
interface
uses
ZConnection, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ZAbstractRODataset, ZAbstractDataset, ZAbstractTable, ZDataset,
StdCtrls, TntStdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
TntMemo1: TTntMemo;
Button2: TButton;
TntEdit1: TTntEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
FZConnection: TZConnection;
FZQuery: TZQuery;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
tntmemo1.Lines.Clear;
FZConnection := TZConnection.Create(Owner);
FZConnection.LoginPrompt := False;
FZQuery := TZQuery.Create(Owner);
FZQuery.Connection := FZConnection;
FZConnection.Protocol := 'mssql';
FZConnection.Database := 'replace-with-your-db';
FZConnection.HostName := 'localhost';
FZConnection.User := 'sa';
FZConnection.Password := 'replace-with-your-password';
FZConnection.Connect;
FZQuery.SQL.Text := 'SELECT * from incominglog';
FZQuery.ExecSQL;
FZQuery.Open;
FZQuery.First;
while not FZQuery.EOF do
begin
tntmemo1.Lines.add(FZQuery.FieldByName('message').AsString);
// tntmemo1.Lines.add(utf8decode(FZQuery.FieldByName('message').AsString)); //inserted as utf8
FZQuery.Next;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
sqlstring, data:widestring;
begin
FZConnection := TZConnection.Create(Owner);
FZConnection.LoginPrompt := False;
FZQuery := TZQuery.Create(Owner);
FZQuery.Connection := FZConnection;
FZConnection.Protocol := 'mssql';
FZConnection.Database := 'replace-with-your-db';
FZConnection.HostName := 'localhost';
FZConnection.User := 'sa';
FZConnection.Password := 'replace-with-your-password';
FZConnection.Connect;
data:= tntedit1.Text;
// data:= utf8encode(tntedit1.Text); //inserted as utf8
sqlstring:= 'INSERT INTO INCOMINGLOG ([MESSAGE]) VALUES(N''' + data + ''')';
FZQuery.SQL.Text := sqlstring;
FZQuery.ExecSQL;
end;
end.
I have not tested your example, but I'm able to save and retrieve from database Unicode characters without problem on SQL Server with Delphi 7 VCL/CLX and zeoslib.
I think in your case it will be enough changing your save procedure like this :
procedure TForm1.Button2Click(Sender: TObject);
var
sqlstring : widestring;
data : UTF8String;
begin
FZConnection := TZConnection.Create(Owner);
FZConnection.LoginPrompt := False;
FZQuery := TZQuery.Create(Owner);
FZQuery.Connection := FZConnection;
FZConnection.Protocol := 'mssql';
FZConnection.Database := 'replace-with-your-db';
FZConnection.HostName := 'localhost';
FZConnection.User := 'sa';
FZConnection.Password := 'replace-with-your-password';
FZConnection.Connect;
data:= UTF8String( utf8encode(tntedit1.Text) );
sqlstring:= 'INSERT INTO INCOMINGLOG ([MESSAGE]) VALUES(:DATA)';
FZQuery.SQL.Text := sqlstring;
FZQuery.ParamByName('DATA').AsString := data;
FZQuery.ExecSQL;
end;
The point is changing your data string variable in UTF8String type, and use parameters pass the data string to the query ...
To be honest I use it with a ZTable and Post command, but it should be the same with a ZQuery like yours ...