Creating a database in Firebird using FireDac (Delphi) - delphi

I recently changed from AnyDac to FireDac (8.0.5.3365). We're running Delphi 2006.
When I was using the AnyDac version of this component I could create a new database by doing the following..
Setup my connection
fConnection.LoginPrompt := false;
fConnection.ResourceOptions.SilentMode := true;
fConnection.Params.Clear;
fConnection.Params.Add(Format('DriverID=%s', ['IB']));
fConnection.Params.Add(Format('Database=%s', [fConnectionInfo.xDatabase]));
fConnection.Params.Add(Format('CharacterSet=%s', ['UTF8']));
fConnection.Params.Add(Format('user_name=%s', [fConnectionInfo.xUserName]));
fConnection.Params.Add(Format('password=%s', [fConnectionInfo.xPassword]));
fConnection.Params.Add(Format('ExtendedMetadata=%s', ['True']));
fConnection.Params.Add(Format('CreateDatabase=%s', ['Yes']));
fConnection.Params.Add(Format('Protocol=%s', ['Local']))
//database path = C:\Users\LoginName\AppData\Local\AppName\TestDB.FDB
Open and close the connection
fConnection.Open;
fConnection.Close;
And then I could run my create table sql scripts on the existing database.
But now when I do this with the FireDac version, the Open command raises the fbe_unavailable error as if I didn't specify the CreateDatabase parameter.
Should I be doing this a different way?
Thanks for your time.
Corey.

You have a full example here http://docwiki.embarcadero.com/RADStudio/Rio/en/Executing_SQL_Scripts_%28FireDAC%29
For example, the following Firebird script creates a database, and can be executed using TFDScript:
SET SQL DIALECT 3;
SET NAMES UTF8;
SET CLIENTLIB 'C:\fb25\bin\fbclient.dll';
CREATE DATABASE 'E:\Test2.ib'
USER 'sysdba' PASSWORD 'masterkey'
PAGE_SIZE 16384
DEFAULT CHARACTER SET NONE;
SET TERM ^ ;
CREATE PROCEDURE MY_PROC RETURNS (aParam INTEGER) AS
BEGIN
aParam = 10;
END^
You should use CreateDatabase=Yes connection definition parameter
additionally to other required parameters:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Connect_to_Firebird_(FireDAC)

Related

UTF8, IBX and Firebird with Euro symbol

I am connecting to Firebird through IBX components in Delphi 10.2 Tokyo.
I'm trying to connect to the DB through the following code:
IBDatabase.Connected := False;
IBDatabase.Params.Clear;
IBDatabase.DatabaseName := FDBFileName;
IBDatabase.Params.Values['user_name'] := FDBUserName;
IBDatabase.Params.Values['password'] := FDBPassword;
IBDatabase.Params.Values['lc_ctype'] := 'UTF8';
IBDatabase.Connected := True;
By trapping the exception during connection, I can realize if the database does not exist, then I create it using the following code:
IBDatabase.Params.Clear;
IBDatabase.DatabaseName := FDBFileName;
IBDatabase.Params.Add('USER ''SYSDBA''');
IBDatabase.Params.Add('PASSWORD ''masterkey''');
IBDatabase.Params.Add('PAGE_SIZE 16384');
IBDatabase.Params.Add('DEFAULT CHARACTER SET UTF8');
IBDatabase.CreateDatabase;
The above operation creates the database and leaves the TIBDatabase component connected to the DB.
In this case, I am creating:
UTF8 string domains
Table with UTF8 field
and setting the Euro symbol (€) in it.
The app opens and the field is visible.
When I restart the app I constantly get an error:
No mapping for the Unicode character exists in the target multi-byte code page
I decided to write this post in order to share the solution I found after almost a week and sleepless nights.
The problem was generated by the creation of the database code.
Since parameters are different and from the usual connection parameters I put DEFAULT CHARACTER SET UTF8, believing that any DDL or statement I was going to operate in the database had the UTF8 character set.
This is not true, the database connection doesn't behave like the one with the lc_ctype parameter set.
To solve this I just had to close connection to the database, reset the parameters like I did the first time:
IBDatabase.Connected:= False;
IBDatabase.Params.Clear;
IBDatabase.DatabaseName:= FDBFileName;
IBDatabase.Params.Values['user_name']:= FDBUserName;
IBDatabase.Params.Values['password']:= FDBPassword;
IBDatabase.Params.Values['lc_ctype']:= 'UTF8';
IBDatabase.Connected:= True;
and do all the operations. This way it works properly.

Error using TADODataset component with MS Access

I am attempting to replace a InterBase DB with a MS Access DB as a test, I am connect to the MS Access DB using the TADOConnection component successfully; however when I try to connect to a table using the TADODataset, I am able to set the Connection property to the TADOConnection component but when I want to set the CommandText property I receive the following error:
The connectionstring is as follows: Provider=ADsDSOObject;User ID=admin;Encrypt Password=False;Data Source=C:\StudyTime\StudyTime.accdb;Mode=Read;Bind Flags=0;ADSI Flag=-2147483648;
Can someone please assist me?
You are using a wrong provider: ADsDSOObject for ms-access.
Use Provider=Microsoft.Jet.OLEDB.4.0 or Provider=Microsoft.ACE.OLEDB.12.0; instead.
e.g.
MdbFileName := 'C:\StudyTime\StudyTime.accdb';
ADOConnection1.ConnectionString := Format('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;', [MdbFileName]);
ADOConnection1.Open;

Parameter value from TUIBQuery gets truncated when read back for Database.Charset=csUTF8

I am working on an application built in Delphi 2010 that uses UIB to connect to a Firebird 2.5 database. The application has been running using the default character set for a long time, i.e. nobody gave character sets any special thought and it has simply been working. Currently I am trying to make it work correctly with UTF-8 data.
In doing so I have hit upon a problem with TUIBQuery and parameterized queries. When using Database.Charset=csUTF8 and setting a parameter value for a CHAR(n)-field and retrieving it before executing the query the value is truncated.
Unfortunately some of my code writes and reads parameter like this in a number of places and therefore dies an ugly death.
To isolate and demonstrate the problem I created a simple fresh database with DEFAULT CHARACTER SET UTF-8 and a table like this:
CREATE TABLE TEST (
CHARFIELD CHAR(20),
VARCHARFIELD VARCHAR(20)
);
I set up the application to connect to the database using TUIBDatabase and TUIBTransaction. Then I created a TUIBQuery-instance, set SQL to a parameterized INSERT-statement into this table, and set the parameters:
Query := TUIBQuery.Create(NIL);
Query.Transaction := Transaction;
Query.SQL.Text := 'INSERT INTO TEST (CHARFIELD, VARCHARFIELD) VALUES (:CHARFIELD, :VARCHARFIELD)';
Query.Prepare(True);
s:= 'ABC';
Query.Params.ByNameAsString['CHARFIELD'] := s;
Query.Params.ByNameAsString['VARCHARFIELD'] := s;
When I now read the parameter-values back like this:
s := Query.Params.ByNameAsString['CHARFIELD'];
s := Query.Params.ByNameAsString['VARCHARFIELD'];
The results are correct for Database.Charset=csNone. But when I instead specify DataBase.Charset=csUTF8 the value for CHARFIELD is truncated to 'A' instead of 'ABC'. The value for VARCHARFIELD is fine. The behaviour is independent of the actual data, I do not have to actually use non-ASCII-characters to provoke it, as the sample shows.
Calling ExecSQL() on the query works correctly and INSERTs the data as expected in both cases.
I have uploaded sourcecode to my simple test program as UIB_UTF8_Test.zip.
Does someone here have any idea what I may be doing wrong and how to do it right?

How to unlock a database after changing CONNECT_PROC

I executed this script in DB2 10.1, and after that, I do not know how to reestablish the database connection:
script.sql
--#SET TERMINATOR #
SET CURRENT SCHEMA BLOCK_DB #
CREATE PROCEDURE BLOCK_DB.A ()
BEGIN
END #
CREATE PROCEDURE BLOCK_DB.B ()
BEGIN
CALL BLOCK_DB.A ();
END #
--#SET TERMINATOR ;
UPDATE DB CFG USING CONNECT_PROC BLOCK_DB.B;
DROP PROCEDURE BLOCK_DB.A ();
CONNECT RESET;
I executed like this
db2 -tf script.sql
After that, I tried to reconnect, but it was unsuccessful.
db2 connect to sample
DO NOT TRY THIS IN A PRODUCTION ENVIRONMENT.
Simply reset the value of CONNECT_PROC:
db2 "update db cfg for <db> using connect_proc ''"
You do not need to have a database connection to execute this statement. This will set CONNECT_PROC back to the default (NULL), and you'll be able to connect to the database again.

Delphi TClientDataSet "Trying to modify read-only field" error in SQL Server 2008, OK in 2000

Embarcadero® Delphi® 2010 Version 14.0.3593.25826
We are attempting to move a database from SQL Server 2000 to SQL Server 2008. I have a TClientDataSet that is loaded with a SELECT that includes a computed column, i.e., "SELECT Comp_Col = Column1 + ' ' + Column2...".
Running against an SQL Server 2000 database, I can modify the value of the column in the TClientDataSet using the following code:
ClientDataSet1.Edit();
ClientDataSet1.FieldByName('Comp_Col').ReadOnly := false;
ClientDataSet1.FieldByName('Comp_Col').Value := 'MODIFIED';
ClientDataSet1.FieldByName('Comp_Col'').ReadOnly := true;
ClientDataSet1.Post(); // <-- EXCEPTION in 2008
Running against an SQL Server 2008 database, though, I get a "Trying to modify read-only field" error when executing .Post().
I have tried also setting .ProviderFlags = '[]' for the column (in addition to .ReadOnly = false) in the above code, but still get the error. I have also tried setting .ReadOnly = false and .ProviderFlags = '[]' at design-time via the IDE, but this does not help either.
Anybody know how to set a computed column in a TClientDataSet when running against an SQL Server 2008 database?
Thanks!
* UPDATE: ANSWERED *
I discovered the problem--or at least a workaround...
I WAS setting .ReadOnly = false for the column in the TClientDataSet object. This worked with SQL Server 2000 but not with SQL Server 2008.
If I set .ReadOnly = false in for the column instead in the TADOQuery object that is serving as the provider, then I am able to set the value of the computed column in the TClientDataSet object at run-time.
Not ideal for me since this was implemented in a generic function for TClientDataSet objects (that didn't anything about the provider), but it will have to do for now.
I discovered the problem--or at least a workaround . . .
I WAS setting .ReadOnly = false for the column in the TClientDataSet object. This worked with SQL Server 2000 but not with SQL Server 2008.
If I set .ReadOnly = false for the column instead in the TADOQuery object that is serving as the provider, then I am able to set the value of the computed column in the TClientDataSet object at run-time.
Not ideal for me since this was implemented in a generic function for TClientDataSet objects (that didn't anything about the provider), but it will have to do for now.
My experience shows that the creation of ClientDataSet fields by calling TClientDataSet.CreaeteDataSet initially without ReadOnly flags solves the problem. After opening ClientDataSet fields' ReadOnly flags can be returned to their seats for the proper functioning of data-aware controls.

Resources