populating data using cursor in oracle forms - oracleforms

I have created a block with 4 text items which i have to populate using a cursor.
I have written a code in the same blocks post-query trigger which is as follows:
DECLARE
CURSOR D_COMM_DET IS
SELECT COMM_SRNO, COMM_SUB_SRNO, COMM_REASON
FROM CUST_COMM
WHERE LEAD_ID = :INQUIRY.INQ_ID; -- master block "INQUIRY"
BEGIN
GO_BLOCK('DISPLAY_DET');
CLEAR_BLOCK('NO_VALIDATE');
FIRST_RECORD;
FOR CUR IN D_COMM_DET
LOOP
:DISPLAY_COMM_DET.A_COMM_SRNO := CUR.COMM_SRNO;
:DISPLAY_COMM_DET.A_COMM_SUB_SRNO := CUR.COMM_SUB_SRNO;
:DISPLAY_COMM_DET.A_COMM_REASON := CUR.COMM_REASON;
NEXT_RECORD;
END LOOP;
FIRST_RECORD;
END;
But this is not populating the data in the text items neither it is showing any errors.
Can anyone help regarding the same.
Thankyou.

You cannot use restricted builtin procedures like GO_BLOCK, CLEAR_BLOCK, NEXT_RECORD in POST-QUERY trigger.
In your case make DISPLAY_COMM_DET block a detail block to INQUIRY block.
Add LEAD_ID item to DISPLAY_COMM_DET block. It can be hidden (Visible=No)
Set DISPLAY_COMM_DET as a database block based on CUST_COMM table
Create a relation on INQUIRY block with relation INQUIRY.INQ_ID=DISPLAY_COMM_DET.LEAD_ID.
Delete POST-QUERY trigger, you don't need it.

I'm not sure if I understand you right. If you need to display reason name from other table, then POST-QUERY trigger is right, but on DISPLAY_COMM_DET block.
Let this block as a detail block based on CUST_COMM table. Create non database item NDB_COMM_REASON_VALUE. Create POST-QUERY trigger on DISPLAY_COMM_DET block like this:
declare
cursor c_reason is
select comm_value
from common_master
where comm_reason = :display_comm_det.comm_reason;
begin
open c_reason;
fetch c_reason into :display_comm_det.ndb_comm_reason_value;
close c_reason;
end;

You cannot use restricted builtin procedures like GO_BLOCK, CLEAR_BLOCK, NEXT_RECORD in POST-QUERY trigger.
Write Execute_Query and the mentioned code in When-Button-Pressed Trigger.

Related

How to show users first and last name in other form when I click on his id or data

I am trying to "connect two forms with mysql" I can't explain it very well.
I want to show users first and last name in other form when I click on him ( Click on his ID or ID Održ or first name or last name.)
How can I do that with MySQL? I am beginner in delphi and MySQL.
This is purely related to Delphi and not the DBMS (MySQL or others). What you are trying to achieve is showing data from your main form's dataset on a second form for details (shown as modal).
You need to be more specific about your implementation :
The location of the dataset : on your main form or on an independent DataModule ?
Also, you didn't specify how the values of selected record will be used in the detail form : In labels, variables, other DB-aware controls ?
Is there a bidirectionnal relationship (Editing on the detail form will edit the record on the main form) ?
Here are the possible steps for your case :
Suppose your dataset control is named ''Dataset'', your main form is ''Form1'', and the detail form is ''Form2''.
First :
If your dataset is on your main form, to avoid circular dependency you have to declare :
The detail form's unit in the Implementation uses a section of the main form's unit.
The main form's unit in the Interface uses a section of the detail form's unit.
If your dataset is on an independent "DataModule", then you have to declare :
The detail form's unit in the Implementation uses a section of the main form's unit.
The DataModule's unit in the Interface uses a section of units of both forms.
Second :
Go to the DBGrid "OnCellClick" event (since you only want to click on the cell), write a code to check the column's FieldName if it is ''Id'' or ''Last Name'' or whatever you want, then show the detail form (ShowModal)
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
//Add whatever fields you want
If (Column.FieldName = 'Id') or (Column.FieldName = 'Last Name') then
Form2.ShowModal;
end;
Third :
In the detail form, there are two possible Implementations :
If you have DB-aware controls (TDBEdit, TDBLabel, ...), then you can set their ''DataSource'' and DataField'' properties to get and exchange data with the dataset, for example ''Form1.Dataset'' or ''DataModule1.Dataset''. And the data will be refreshed everytime the detail form is shown.
If you want to use the values of the selected records in variables or a custom logic (like changing a TLabel's caption to something like ''User is %s with id %u'', or as foreign key for filtering another dataset), then you have to get and set those values in the detail form ''OnShow'' event, like in this example :
procedure TForm2.FormShow(Sender: TObject);
begin
Label1.Caption := Format('Details of %s %s - Id : %u', [Form1.Dataset.FirstNameField.AsString, Form1.Dataset.LastNameField.AsString, Form1.Dataset.IdField.AsInteger]);
end;
Or like this :
procedure TForm2.FormShow(Sender: TObject);
var
FirstName, LastName: string;
Id: Integer;
begin
FirstName := Form1.Dataset.FirstNameField.AsString;
LastName := Form1.Dataset.LastNameField.AsString;
Id := Form1.Dataset.IdField.AsInteger;
end;
Fourth :
There is a known issue, the second form ''OnShow" event is fired only on the first call to ''ShowModal'' after form creation, and not in subsequent calls.
As a workaround, you have to either release or hide the detail form when you close it.
You can do this through the detail form ''OnClose'' event, by setting a value for the close action (''caFree'' or ''caHide'').
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caHide;
end;
Fifth :
If you want to update the current record from the detail form, you have to put a control (like a button) for validation in the detail form with an "OnClick" event handler that will commit the changes to the dataset and close the detail form.
There is also the form's ''ModalResult'' property that, when assigned a non-zero value, will close the modal form and return that value to the function ''ShowModal'' called in the main form :
If you use this property, then the validation button on the detail form must assign the returned value, and on the main form you have to check the returned value and receive updated values as variables from the detail.
But you can also avoid using it in order to keep the update logic on the detail form.
If you call the Close method in a modal form, then "ModalResult" is automatically set to "mrCancel".
Here is an example for updating the record without need for ''ModalResult''property (if your dataset is on a DataModule, then replace "Form1" with the name of the DataModule) :
procedure TForm2.BtnSaveClick(Sender: TObject);
begin
try
Form1.Dataset.Edit;
try
Form1.Dataset.FirstNameField.AsString := EditFirstName.Caption;
Form1.Dataset.LastNameField.AsString := EditLastName.Caption;
Form1.Dataset.Post;
except
Form1.Dataset.Cancel;
end;
finally
Close;
end;
end;

how to show more than one result on query

I have a procedure on MySQL that returns two results and I need to show this on Delphi but I didn't find how to pass for each result.
Here is how appear on DBForge when I execute, I want this on delphi too, show Query1 and Query2 in a TTabControl.
How to go through this queries and get the name of the query like: Query1,Query2?
You don't say what DB interface lib you're using, like FireDAC, Zeos, or something else.
You're going to issue something like a dbxyz.ExecSQL() call and check for some results.
It sounds like you're expecting to get back multiple records in the result set. Using a TTabControl, you'd simply create a list of tabs like "Result-1", "Result-2", and so on, depending on how many records you get back. (They're results, not queries.) You could select the first one by default.
When another tab is clicked, use the control's TabIndex property to select the corresponding result from the result set, then format up the data in that result and display it in whatever format you're using below the tabs.
There's so little detail you've given that it's impossible to show any code for anything other than the tab control's OnChange handler that will use the TabIndex property to find the desired result set. But this is the overall approach I'd take for this using the TTabControl.
I solve the problem with the command
var
tab: TTabItem;
stringGrid: TStringGrid;
repeat
tab:= TTabItem.Create(nil);
tab.Parent:= tabcontrol1;
tab.Text:= query.Fields.Fields[0].FieldName; //the table name
stringGrid:= TStringGrid.Create(Self);
stringGrid.Parent:= tab;
stringGrid.Align:= TAlignLayout.Client;
for I := 1 to query.FieldCount-1 do
begin
stringGrid.AddObject(TStringColumn.Create(stringGrid));
stringGrid.Columns[i-1].Header:= query.Fields.Fields[i].FieldName;
query.First;
for j := 0 to query.RecordCount-1 do
begin
stringGrid.cells[i-1, j]:= query.Fields.Fields[i].value;
query.Next;
end;
end;
stringGrid.RowCount:= j;
until not query.openNext;

Trying to save a .bmp from PC to a database blob field

I'm trying to save a .bmp from my PC to a database that contains a blob field.
I am currently working with code from here:
How to insert image into database using TADOQuery Component Only
I've created a new form and added necessary components there.
This is how the form looks like:
It contains the following: 3 TButton, 1 TOpenDialog and 1 TImage
Button Salveaza (Save) is Button3 and has ModalResult set to mrOk
Button Incarca Imagine (Load Image) is Button1
Button Cancel is Button2, has Cancel property ticked and has ModalResult set to mrAbort
The code for the Incarca Imagine (Button1) button is this:
procedure TaddImagineForm.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
Image1.Picture.LoadFromFile(OpenDialog1.FileName);
end;
end;
The code for button named Salveaza (Button3) is:
procedure TaddImagineForm.Button3Click(Sender: TObject);
var
Field: TBlobField;
Stream: TStream;
begin
if dbmodule.comenziQuery.Active and (Image1.Picture.Graphic <> nil) then
begin
dbmodule.comenziQuery.Insert;
Field := TBlobField(dbmodule.comenziQuery.FieldByName('pscreen')); // ensure it ís a blob
Stream := dbmodule.comenziQuery.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
dbmodule.comenziQuery.Post;
end;
end;
end;
The TSQLQuery I'm using (named comenziQuery) is located on a Data module, along with other things I'm using (like DataSource, DataSet, SQLConnection and so on..) the Data module is named dbmodule
The column in the database that should hold the .bmp image is named pscreen and is set as a mediumblob type.
What should happen (in probably my newbie point of view)
The blob field named pscreen for the selected row should now contain the .bmp I selected previously with my TOpenDialog, by pressing the Incarca Imagine button
What's actually hapenning
Once I click the Save button the form closes but the selected row doesn't get updated with the bmp image in it's blob field. No error, no warning, nothing. The field remains NULL for that row.
EDIT
Thanks to Dsm in the comments he pointed out that I'm using an insert, which adds a new record, not updates the one I'm selecting.
I'm referring to this line: dbmodule.comenziQuery.Insert;
Need to change the code somehow to update the record I'm selecting.
Extremely new to Delphi/SQL so I do apologize if it seems I'm banging my head against a wall and doing the exact opposite.
I'm using Rad Studio 10 Seattle, the database is MYSQL, the database components are located on a data module named dbmodule and contain the following: TSimpleDataSet, TSQLQuery, TDataSource, TSQLConnection - they are dbExpress components.
Thank you!
The following code worked and was successful in providing the functionality that I needed
procedure TaddImagineForm.Button3Click(Sender: TObject);
var
Field: TBlobField;
Stream: TStream;
begin
dbmodule.comenziDataSet.Active := True;
if (Image1.Picture.Graphic <> nil) then
begin
dbmodule.comenziDataSet.Edit;
Field := TBlobField(dbmodule.comenziDataSet.FieldByName('pscreen')); // ensure it ís a blob
Stream := dbmodule.comenziDataSet.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
dbmodule.comenziDataSet.Post;
end;
end;
end;
end.
Just replaced using the Query with using the DataSet and that seems to have solved it, also my original post / question was wrong as I've been confusing the problems. Still, good for anyone going through the same.
Thanks to Sertac Akyuz

Oracle Forms Execute_query giving FRM-40737 error

I am getting an error
FRM - 40737 - illegal restricted procedure GO_BLOCK in
WHEN-VALIDATE-RECORD trigger.
My Code is
IF event_name = 'WHEN-VALIDATE-RECORD'
THEN
IF (form_name = 'OEXOEORD' AND block_name = 'ORDER')
THEN
-- call procedure to validate and cascade the ship method code.
cascade_ship_method;
execute_query;
END IF;
What am I doing wrong here ?
This is because Oracle Forms has two types of built-in procedures - restricted and unrestricted. Some triggers enable restricted procedures, some not (see Oracle Forms help, every trigger has information which procedures it enables).
Trigger WHEN-VALIDATE-ITEM fires for example when user moves cursor from one record to the other (this is called navigation). In this case it leaves one record and enters other. There is fired following chain of triggers
WHEN-VALIDATE-ITEM
WHEN-VALIDATE-RECORD
POST-ITEM
POST-RECORD
PRE-RECORD
PRE-ITEM
If any of this trigger fails, navigation is canceled and cursor returns to the original item. If you call any procedure, which starts new navigation (like GO_BLOCK), Oracle Forms would not be able to manage first navigation.
This is, why some procedures are restricted.
It might be relevant with content of cascade_ship_method. When I got this error, I had missed an apostrophe in the SET_BLOCK_PROPERTY statement. When I fixed, it worked. This is the correct structure in my code block:
SET_BLOCK_PROPERTY (
'TABLE_A',
default_where,
'column_a= '
|| ''''
|| variable
|| '''');

MySQL trigger not working properly

I'm getting a strange error while trying to use a MySQL trigger.
I'm using XAMPP and creating the trigger using PhpMyAdmin.
The trigger's code is:
BEGIN
DECLARE stud INT(11) DEFAULT 0;
DECLARE sw CURSOR FOR
(SELECT CodiceStudente FROM Listastudenticorsi WHERE CodiceCorso = NEW.CodiceCorso);
OPEN sw;
get_loop: LOOP
FETCH sw INTO stud;
INSERT INTO inbox(Mittente, Destinatario, Oggetto, Contenuto, Data) VALUES (NEW.CodiceDocente, stud, "Nuova news inserita", NEW.Oggetto, NEW.Data);
END LOOP get_loop;
END
And is called BEFORE INSERT into the table 'News'.
What happens is that the syntax is correct, but when I try to run it triggering the event it says "#1329 - No data - zero rows fetched, selected, or processed".
I tried to find out what the real problem is, and it seems to be the line "FETCH sw INTO stud"; I tried many times and the SELECT statement DOES return the correct values, so 'sw' can't be empty... I'm stuck at this point.
There are 3 tables interested by this trigger. 'News' is the one that triggers the event; it has some columns that are called using the keyword "NEW". The second one is Inbox; it is the table in which I'll insert some values after the trigger has performed its actions. Finally, there's "Listastudenticorsi", which means approximately "list of students and courses".
What I do is: when a News is inserted, I get the course it refers to, its object, its date and the submitter of the news, I find (using the select statement) the students who attend the course that the News is referring to, and then send a mail to each of them using the insert statement.
You have no continue handler for the cursor, as I see it. It would allow that cursor to actually do something.
From the mysql Cursor manual page, see this.
Here too is a link to a stored proc I wrote showing a continue handler with a flag specifying done for the loop.