Receiving syntax error while using ADOQuery to insert into database - ado

All names and data types were checked to ensure no incorrect info/fields were used.
A with Datamodule was stated at the top of the code, but there is too much to post from the rest, this is the only part which doesn't work:
sEncPass := objAlgorithms.CipherEn(sPass,13);
//start insert code
qryUserInfo.SQL.Clear;
qryUserInfo.SQL.Add('INSERT INTO LoginInfo(ID,Login,Password)');
qryUserInfo.SQL.Add('VALUES(:ID,:Login,:Password)');
with qryUserInfo.Parameters do
begin
ParamByName('ID').Value := sID;
ParamByName('Login').Value := sUsername;
ParamByName('Password').Value := sEncPass;
end;
qryUserInfo.ExecSQL;
qryUserInfo.SQL.Clear;
qryUserInfo.SQL.Add('INSERT INTO CustomerInfo(ID,Name,Surname,TelNo,Email)');
qryUserInfo.SQL.Add('VALUES (:ID,:Name,:Surname,:TelNo,:Email)');
with qryUserInfo.Parameters do
begin
ParamByName('ID').Value := sID;
ParamByName('Name').Value:= sName;
ParamByName('Surname').Value:= sSurname;
ParamByName('TelNo').Value:= sCell;
ParamByName('Email').Value:= sRAddres;
end;
qryUserInfo.ExecSQL;
The fields I am using in the DB (all are strings):

Thanks everyone who helped, found a fix by adding ` to the field names:
qryUserInfo.SQL.Add('INSERT INTO CustomerInfo(`ID`,`Name`,`Surname`,`TelNo`,`Email`)');

Related

FireDAC DBMS Identifiers for conditional statement

I'm trying to use the FireDAC DBMS Identifiers for generating a database specific query.
I'm connecting to a MySQL-Server currently (DriverID = MySQL). I want to query either from mysql or mssql with a limit / top query.
My current statement looks like this:
SELECT
{IF MSSQL} TOP(1) {fi} `tr`.`TaxRate_Primkey`
FROM
`tbl_taxrates` AS `tr`
WHERE
`tr`.`TaxRate_TaxCodeId` = `tc`.`TaxCode_Primkey`
AND
`tr`.`TaxRate_ValidSince` <= :DATE
ORDER BY `tr`.`TaxRate_ValidSince` DESC
{IF MySQL} LIMIT 1 {fi}
Of course I'm aware, that the escaping will not be correct for mssql, but that's a different story.
When I inspect the FireDAC Monitor the preprocessed query looks like this:
SELECT
TOP(1) `tr`.`TaxRate_Primkey`
FROM
`tbl_taxrates` AS `tr`
WHERE
`tr`.`TaxRate_TaxCodeId` = `tc`.`TaxCode_Primkey`
AND
`tr`.`TaxRate_ValidSince` <= ?
ORDER BY
`tr`.`TaxRate_ValidSince` DESC
LIMIT 1
Of course this will result in error
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.`TaxRate_Primkey` FROM `tbl_taxrates` AS `tr` WHERE `tr`.`TaxRate_TaxCodeId` ' at line 1 [errno=1064, sqlstate="42000"]
since it should only add the LIMIT 1 and omit the TOP(1).
Since I only have the Delphi Community Edition 10.4, I don't have access to the MSSQL-Driver. I thought, that could cause this error and I tried with others. But also with {if FIREBIRD} and {if ADS} it was the same.
The constructor looks like this:
constructor TFireDACTenantRepository.Create(
ADBName: string;
ADBServer: string;
APort: Integer;
AUserName: string;
APassword: string;
ALogger: TLogger
);
var
oParams: TStrings;
begin
inherited Create;
FLogger := ALogger;
Self.MonitorLink := nil;
Self.MonitorBy := mbRemote;
Self.Tracing := True;
FConnection := TFDConnection.Create(nil);
oParams := TStringList.Create;
try
oParams.Add('Server=' + ADBServer);
oParams.Add('Port=' + IntToStr(APort));
oParams.Add('Database=' + ADBName);
oParams.Add('User_Name=' + AUserName);
oParams.Add('Password=' + APassword);
oParams.Add('OSAuthent=No');
FDManager.AddConnectionDef('MySQLConnectionTenant', 'MySQL', oParams);
FConnection.Params.MonitorBy := Self.MonitorBy;
FConnection.ConnectionDefName := 'MySQLConnectionTenant';
FConnection.ResourceOptions.ParamCreate := True;
FConnection.ResourceOptions.MacroCreate := True;
FConnection.ResourceOptions.ParamExpand := True;
FConnection.ResourceOptions.MacroExpand := True;
FConnection.ResourceOptions.PreprocessCmdText := True;
FConnection.ResourceOptions.EscapeExpand := True;
finally
oParams.Free;
end;
FConnection.AfterConnect := DoAfterConnect;
FConnection.AfterDisconnect := DoAfterDisconnect;
end;
My question looks a bit related to this question here
How do I use FireDAC DBMS identifiers to conditionally change SQL text
Thanks
I found the solution. If you want to use the conditional escape sequence, you also have to use the FireDAC.Phys.XXX unit for all involved databases.
Since I want to use MSSQL, I have to add FireDAC.Phys.MSSQL to the use-clause.
The units are listed here:
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Databases_(FireDAC)
Maybe this answer helps others.

Delphi7, Save User's Changes or other User's Information / Notes

In my program, the user completes a form and then presses Submit. Then, a textfile or a random extension file is created, in which all the user's information is written. So, whenever the user runs the application form, it will check if the file, which has all the information, exists, then it copies the information and pastes it to the form. However, it is not working for some reason (no syntax errors):
procedure TForm1.FormCreate(Sender: TObject);
var
filedest: string;
f: TextFile;
info: array[1..12] of string;
begin
filedest := ExtractFilePath(ParamStr(0)) + 'User\Identity\IdentityofMyself.txt';
if FileExists(filedest) then
begin
AssignFile(f,filedest);
Reset(f);
ReadLn(info[1], info[2], info[3], info[4], info[5], info[6], info[7],
info[8], info[9], info[10], info[11], info[12]);
Edit1.Text := info[1];
Edit2.Text := info[2];
ComboBox1.Text := info[3];
ComboBox5.Text := info[4];
ComboBox8.Text := info[4];
ComboBox6.Text := info[5];
ComboBox7.Text := info[6];
Edit3.Text := info[7];
Edit4.Text := info[8];
Edit5.Text := info[11];
Edit6.Text := info[12];
ComboBox9.Text := info[9];
ComboBox10.Text := info[10];
CloseFile(f);
end
else
begin
ShowMessage('File not found');
end;
end;
The file exists, but it shows the message File not found. I don't understand.
I took the liberty of formatting the code for you. Do you see the difference (before, after)? Also, if I were you, I would name the controls better. Instead of Edit1, Edit2, Edit3 etc. you could use eFirstName, eLastName, eEmailAddr, etc. Otherwise it will become a PITA to maintain the code, and you will be likely to confuse e.g. ComboBox7 with ComboBox4.
One concrete problem with your code is this line:
readln(info[1], info[2], info[3], info[4], info[5], info[6], info[7],
info[8], info[9], info[10], info[11], info[12]);
You forgot to specify the file f!
Also, before I formatted your code, the final end of the procedure was missing. Maybe your blocks are incorrect in your actual code, so that ShowMessage will be displayed even if the file exists? (Yet another reason to format your code properly...)
If I encountered this problem and wanted to do some quick debugging, I'd insert
ShowMessage(BoolToStr(FileExists(filedest), true));
Exit;
just after the line
filedest := ...
just to see what the returned value of FileExists(filedest) is. (Of course, you could also set a breakpoint and use the debugger.)
If you get false, you probably wonder what in the world filedest actually contains: Well, replace the 'debugging code' above with this one:
ShowMessage(filedest);
Exit;
Then use Windows Explorer (or better yet: the command prompt) to see if the file really is there or not.
I'd like to mention an another possibility to output a debug message (assuming we do not know how to operate real debugger yet):
{ ... }
filedest := ExtractFilePath(ParamStr(0)) + 'User\Identity\IdentityofMyself.txt';
AllocConsole; // create console window (uses Windows module) - required(!)
WriteLn('"' + filedest + '"'); // and output the value to verify
if FileExists(filedest) then
{ ... }

MS Word 2010 mailmerge in Delphi 5

could anyone help?
I've inherited some software written in Delphi 5 which allows member data and fields from a database (.ADT file) to be used merged in to word.
It works fine with all version of Word except 2010 where it won't load any documents and shows the error:
"That Method is not available on that object"
I have been told the solution is to replace the preset components OpWord and OpDataSet with Ole variants. I have done so with OpWord using:
wrdApp := CreateOleObject('Word.Application');
and the documents now load up but without any merge field data. Can anyone let me know how to extract this data from the database, as the OpDataSet seems to simply just point at the table?
Or can anyone suggest a better solution than the one I'm trying. I'm very new to Delphi so I'm in abit over my head
Edit: (Requested Info)
Sorry I have more details and code if required.
The components appear to belong to a library called OfficePartner along with TOpExcel,TOpOutlook and others.
The .doc is selected from a popup ListPane on Form30, opened and populated with merge field data from Table 4. Table 1 is the members database:
{Use Table4 as we can Set a range on it}
Table4.SetRange([Table1.FieldByName('Member Id').AsString],[Table1.FieldByName('Member Id').AsString]);
{Open Word}
OpWord1.Connected := True;
{Open the Test Document}
OpWord1.OpenDocument(DocumentDirectory + '\' + Form30.ListBox1.Items[Form30.ListBox1.ItemIndex]);
{Populate the Test Document}
OpWord1.ActiveDocument.MailMerge.OfficeModel := OpDataSetModel1;
OpWord1.ActiveDocument.PopulateMailMerge;
OpWord1.ActiveDocument.ExecuteMailMerge;
I hope this helps...
Here is a little procedure for word mail merge that I used way back for D6, it's a just snippet and you have to include in some class, I don't have Delphi anymore so can't compile to make sure that it works, anyway here it is, hope it helps:
procedure MailMergeWord;
var
WordApp: TWordApplication;
WordDoc: TWordDocument;
doc : WordDocument;
FileName: OleVariant;
xx: integer;
begin
WordApp := TWordApplication.Create(nil);
WordApp.ConnectKind := ckNewInstance;
WordDoc := TWordDocument.Create(WordApp);
FileName := 'TemplateDoc.doc';
doc := WordApp.Documents.Open(FileName,EmptyParam,EmptyParam,EmptyParam,EmptyParam
,EmptyParam,EmptyParam,EmptyParam,EmptyParam
,EmptyParam);
WordDoc.ConnectTo(Doc);
for xx := 1 to WordDoc.Fields.Count do
WordDoc.Fields.Item(xx).Result.Text := OnWordVariable(WordDoc.Fields.Item(xx).Code.Text);
WordDoc.PrintOut;
WordDoc.Free;
WordApp.Free;
end;
function OnWordVariable(varName: string): string;
begin
Result := 'Value based on variable name';
end;

Delphi ODAC: Disecting JMS messages from Oracle AQ

I'm trying to evaluate ODAC for using Oracle AQ.
The request queue contains JMS objects like these (but without linebreaks and other whitespace):
SYS.AQ$_JMS_BYTES_MESSAGE(
SYS.AQ$_JMS_HEADER(
'null','null','null','null','null','null',
SYS.AQ$_JMS_USERPROPARRAY(
SYS.AQ$_JMS_USERPROPERTY('Key1',100,'Value1','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key2',100,'Value2','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key3',100,'Value3','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key4',100,'Value4','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key5',100,'Value5','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key6',100,'Value6','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key7',100,'Value7','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key8',100,'Value8','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key9',100,'Value9','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key10',100,'Value10.0','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key11',100,'Value11','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key12',100,'Value12','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key13',100,'Value13','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key14',100,'Value14','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key15',100,'Value15','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key16',100,'Value16','null',27),
SYS.AQ$_JMS_USERPROPERTY('Key17',100,'Value17','null',27)
)
),
4168,'null','oracle.sql.BLOB#959acc'
)
I can receive the underlying object (a string Payload comes back as an empty string, but a TOraObject PayLoad contains data).
I'm trying to disscect the TOraObject PayLoad, and am looking for a table that converts the DataType values into the correct AttrXxxx[Name] property calls.
OraType.AttributeCount:4
OraType.Name:"SYS"."AQ$_JMS_BYTES_MESSAGE"
OraType.DataType:15
Attribute[0].Name:HEADER
Attribute[0].DataType:15
OraType.AttributeCount:7
OraType.Name:"SYS"."AQ$_JMS_HEADER"
OraType.DataType:15
Attribute[0].Name:REPLYTO
Attribute[0].DataType:15
OraType.AttributeCount:3
OraType.Name:"SYS"."AQ$_AGENT"
OraType.DataType:15
Attribute[0].Name:NAME
Attribute[0].DataType:1
Attribute[1].Name:ADDRESS
Attribute[1].DataType:1
Attribute[2].Name:PROTOCOL
Attribute[2].DataType:5
Attribute[1].Name:TYPE
Attribute[1].DataType:1
Attribute[2].Name:USERID
Attribute[2].DataType:1
Attribute[3].Name:APPID
Attribute[3].DataType:1
Attribute[4].Name:GROUPID
Attribute[4].DataType:1
Attribute[5].Name:GROUPSEQ
Attribute[5].DataType:5
Attribute[6].Name:PROPERTIES
Attribute[6].DataType:17
OraType.AttributeCount:1
OraType.Name:"SYS"."AQ$_JMS_USERPROPARRAY"
OraType.DataType:17
Attribute[0].Name:ELEMENT
Attribute[0].DataType:15
OraType.AttributeCount:5
OraType.Name:"SYS"."AQ$_JMS_USERPROPERTY"
OraType.DataType:15
Attribute[0].Name:NAME
Attribute[0].DataType:1
Attribute[1].Name:TYPE
Attribute[1].DataType:5
Attribute[2].Name:STR_VALUE
Attribute[2].DataType:1
Attribute[3].Name:NUM_VALUE
Attribute[3].DataType:5
Attribute[4].Name:JAVA_TYPE
Attribute[4].DataType:5
Attribute[1].Name:BYTES_LEN
Attribute[1].DataType:5
Attribute[2].Name:BYTES_RAW
Attribute[2].DataType:1
Attribute[3].Name:BYTES_LOB
Attribute[3].DataType:102
By trial and error, I have come so far:
case DataType of
102:
LOB := ObjectPayLoad.AttrAsLob[Name];
15:
AttributeOraObject := ObjectPayLoad.AttrAsObject[Name];
17:
AttributeOraArray := ObjectPayLoad.AttrAsArray[Name];
else
begin
PayLoadAttributeAsString := ObjectPayLoad. AttrAsString[Name];
Logger.Log(' "%s"', [PayLoadAttributeAsString]);
end;
end;
A more complete list is welcome :-)
After this, I will need to research the other way around: generating the right TOraObject that has a JMS content in it.
Tips for that are also welcome.
--jeroen
Edit:
ODAC has multiple units defining constants.
The constant dtOraBlob with value 102 is in the OraClasses unit; constants defining DataType values start with the prefix dt, regardless of the unit that defines them.
Original:
I have found a few of these constants in the MemData unit:
case DataType of
102:
LOB := OraObject.AttrAsLob[Name];
MemData.dtObject: // 15
begin
AttributeOraObject := OraObject.AttrAsObject[Name];
LogOraObject(AttributeOraObject, Level+1);
end;
MemData.dtArray: // 17
begin
AttributeOraArray := OraObject.AttrAsArray[Name];
LogOraArray(AttributeOraArray, Level);
end;
MemData.dtFloat: // 5
begin
AttributeFloat := OraObject.AttrAsFloat[Name];
Logger.Log(Prefix+'"%g"', [AttributeFloat]);
end;
MemData.dtString: // 1
begin
PayLoadAttributeAsString := OraObject.AttrAsString[Name];
Logger.Log(Prefix+'"%s"', [PayLoadAttributeAsString]);
end;
else
begin
PayLoadAttributeAsString := OraObject.AttrAsString[Name];
Logger.Log(Prefix+'"%s"', [PayLoadAttributeAsString]);
end;
end;
I can't find the 102 constant though, but I'm pretty sure it is for a LOB field.
Anyone who can confirm that?
--jeroen

Delphi 5 & Crystal XI Rel. 2 (RDC) how to?

I'm trying to work with the class from JosephStyons but I do get an "Invalid Index" Error on the line where the "User ID" should get set.
FRpt.Database.Tables[i].ConnectionProperties.Item['User ID'] := edUserName.Text;
Here's my environment:
WinXP Sp3, Crystal Reports Developer XI Rel.2 SP4, Delphi 5 Update Pack 1
Any help or ideas greatly appreciated!
Thx,
Reinhard
Your value for [i] could be the culprit...I can't remember for sure but I believe the first table will be Table[1] instead of Table[0] as one would expect.
I altered my loop to use:
CrTables := CrDatabase.Tables;
for crTableObj in crTables do
You might try stepping through the table using a for loop as shown above or by starting with 1 instead of 0.
I hope this helps.
Put a break point on that line and use Evaluate/Modify.
It will return an error if you try something invalid.
Examine FRpt.Database.Tables[i] and see if it's valid for what you think are the min and max values for i.
If Tables is an array, one way to avoid that is to use ...Low(Tables) to High(Tables)
If you get your Table Ok, examine FRpt.Database.Tables[i].ConnectionProperties.Item['User ID'] and see if it's valid.
It might be that the Item getter does not like the space embedded in "User ID". Some products need either to surround by special characters like "[User ID]", other to replace by an underscore like "User_ID"
Are you also setting the password, server name and database name?
procedure TReports.LogonToDBTables(cReport:
CrystalDecisions.CrystalReports.Engine.ReportDocument;
ConnInfo: ConnectionInfo);
var
CrDataBase: Database;
CrTables: Tables;
CrTableObj: TObject;
CrTable: Table;
CrTableLogonInfo: TableLogonInfo;
iSubReportIndex: smallint;
begin
CrDataBase := CReport.Database;
CrTables := CrDatabase.Tables;
cReport.DataSourceConnections[0].IntegratedSecurity := False;
for crTableObj in crTables do
begin
crTable := CrystalDecisions.CrystalReports.Engine.Table(crTableObj);
crTableLogonInfo := crTable.LogOnInfo;
crTableLogonInfo.ConnectionInfo := ConnInfo;
crTable.ApplyLogOnInfo(crTableLogonInfo);
end;
end;
function TReports.GetConnectionInfo(): ConnectionInfo;
var
cTemp: ConnectionInfo;
begin
cTemp := ConnectionInfo.Create();
cTemp.AllowCustomConnection := True;
cTemp.ServerName := GetServerName();
cTemp.DatabaseName := GetDBName();
cTemp.UserID := GetDBUserID();
cTemp.Password := GetDBPassword();
Result := cTemp;
end;

Resources