PL/pgSQL: cannot find output of "raise notice" statements - printing

The stored procedure sp_test contains several print-statements such as:
raise notice 'TEST !!!!!!';
However, when I execute the following script:
select *
from sp_test (v_par1 := 1,
v_debugmode := 1 );
... a result set is returned but I don't see anything of the "raise notice"-statements.
Where are these print-statements printed to (where can I find the output of these print statements)?

It depends on client and notification level. psql notices displays directly, pgAdmin in special tab. Check value of configuration variable client_min_messages. Is possible set filter, and notices are not send to client.

Related

DB2-12 (Z/OS) - Create Alias for Stored Procedure

it's possible to define an alias for a stored procedure (sql-native)?
In the documentation, reference is made only to: SEQUENCE and TABLES
1) CREATE PROCEDURE OWXXCOLL.STORED1()
2) CREATE ALIAS DB2C.STORED1 FOR OWXXCOLL.STORED1;
3) CALL DB2C.STORED1();
EDIT 2021-05-14
The original question arises for the following problem (I was hoping to get away with using aliases)
Intro
I have defined a native SP
The OWXXCOLL schema is the same one I also use for tables/index...
(I noticed that the tables also have different aliases)
CREATE PROCEDURE OWXXCOLL.STORED1(...)
LANGUAGE SQL
ISOLATION LEVEL CS
WLM ENVIRONMENT FOR DEBUG MODE WLMENV1
ALLOW DEBUG MODE
BEGIN
...
END#
I also modified the cobol program (name:PGMSTO1) to call the Stored with the CALL statement (without qualifier)
EXEC SQL
CALL STORED1 (...)
END-EXEC.
The problem
The various table accesses (SELECT) work correctly BUT When I run the PGMSTO1 the call to the Stored ends with sqlcode -440
NO AUTHORIZED PROCEDURE BY THE NAME STORED1 HAVING COMPATIBLE ARGUMENTS WAS FOUND<
The error comes from the fact that it is not using the owner OWXXCOLL but DB2C (DB2C is user who scheduled the jcl/batch)
If I enter the qualifier (OWXXCOLL) the call it's OK.
I don't understand what to check and what configurations are missing.
Thanks
The cobol program (PGMSTO1) that calls the stored procedure has the following BIND parameters:
COLLID NAME OWNER CREATOR QUALIFIER DYNAMICRULES PATHSCHEMAS
OWXXCOLL PGMSTO1 DB2C DB2C FPXX B "DB2C"
"DB2C" path is used to resolve unqualified stored procedure
I will need to modify the bind parameter "PATH".
I will try to ask to add my schema as well (OWXXCOLL)
PATH("OWXXCOLL","DB2C")

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?

Imap4 client command LSUB

I have a problem with function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean; with this implementation :
function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean;
begin
{CC2: This is one of the few cases where the server can return only "OK completed"
meaning that the user has no subscribed mailboxes.}
Result := False;
CheckConnectionState([csAuthenticated, csSelected]);
SendCmd(NewCmdCounter, IMAP4Commands[cmdLSub] + ' "" *',
[IMAP4Commands[cmdList], IMAP4Commands[cmdLSub]]); {Do not Localize}
if LastCmdResult.Code = IMAP_OK then begin
// ds - fixed bug # 506026
ParseLSubResult(AMailBoxList, LastCmdResult.Text);
Result := True;
end;
end;
When I debug I see that the LastCmdResult.Text stringlist is empty, but the LastCmdResult.FormattedReply stringlist has all folders on my email server (Inbox, Sent, Trash, ...). When I tried to use LastCmdResult.FormattedReply count or text, it had immediately lost its data and gave LastCmdResult.FormattedReply.Count=0 and LastCmdResult.FormattedReply.Text=''. So I'd like to know if there is a way to enter the data inside LastCmdResult.FormattedReply and get my email server folders or there is another way to solve my problem ?
I have a problem with function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean; with this implementation :
Works fine for me when I try it using the latest SVN version of Indy.
When I debug I see that the LastCmdResult.Text stringlist is empty, but the LastCmdResult.FormattedReply stringlist has all folders on my email server (Inbox, Sent, Trash, ...).
When I run it, the opposite happens. LastCmdResult.Text contains the expected text, and LastCmdResult.FFormattedReply is empty (notice I mention the FFormattedReply data member directly, see below).
When I tried to use LastCmdResult.FormattedReply count or text, it had immediately lost its data and gave LastCmdResult.FormattedReply.Count=0 and LastCmdResult.FormattedReply.Text=''.
That is by design. The FormattedReply property is intended to be used by a client to parse a server reply so it can populate TIdReply's property values, and to be used by a server to generate a new reply using TIdReply's property values. So, you cannot read from the FormattedReply property on the client side.
So I'd like to know if there is a way to enter the data inside LastCmdResult.FormattedReply and get my email server folders or there is another way to solve my problem ?
The whole purpose of ListSubscribedMailBoxes() is to return the folder names in the AMailBoxList parameter. If that is not working for you, then either
you are using a older/buggy version of Indy.
your server is sending the data in a format that TIdIMAP4 is not able to parse.
Without knowing which version of Indy you are actually using, or what the server's reply data actually looks like, there is no way to diagnose your issue one way or the other.

Delphi Bug in Indy FTP List method?

I'm trying to generate a list of files matching a certain file mask and Indy falls over with this error
EidReplyRFCError with message '.': No such file or directory.
I've tried several variations and this is the result:
FTP.List( aFiles, '', true ); => this works
FTP.List( aFiles, '*.*', false ); => this works too
FTP.List( aFiles, '*.*', true ); => this fails
FTP.List( aFiles, '*.zip', true ); => this fails too (despite it being the example in the latest documentation)
FTP.List( '*.*', false ); => this works
FTP.List( '*.*', true ); => this fails
I'm using Delphi XE5 & Indy version 10.6. The same issue exists in XE8 if relevant.
Maybe the functionality has changed and the documentation is now wrong or it's a bug in Indy?
I need the "details" so I can compare timestamps & sizes too.
This is not a bug in TIdFTP. It is more an omission in the Indy documentation.
EIdReplyRFCError means the FTP server itself is reporting an error in response to the command that TIdFTP.List() is sending. Depending on the values of the ADetails parameter and TIdFTP's UseMLIS+CanUseMLS properties, List() can send one of three different commands:
ADetails=False:
NLST [ASpecifier]
ADetails=True:
TIdFTP.UseMLIS=True and TIdFTP.CanUseMLS=True:
MLSD [ASpecifier]
TIdFTP.UseMLIS=False or TIdFTP.CanUseMLS=False:
LIST [ASpecifier]
Thus:
FTP.List( aFiles, '', true ); // this works
// sends either 'LIST' or 'MLSD'
FTP.List( aFiles, '*.*', false ); // this works too
// sends 'NLST *.*'
FTP.List( aFiles, '*.*', true ); // this fails
// sends either 'LIST *.*' or 'MLSD *.*'
FTP.List( aFiles, '*.zip', true ); // this fails too
// sends either 'LIST *.zip' or 'MLSD *.zip'
FTP.List( '*.*', false ); // this works
// sends 'NLST *.*'
FTP.List( '*.*', true ); // this fails
// sends either 'LIST *.*' or 'MLSD *.*'
Note that all of the commands that "fail" have something in common - they might be sending an MLSD ASpecifier command.
Per RFC 959, which defines the LIST and NLST commands:
LIST (LIST)
This command causes a list to be sent from the server to the
passive DTP. If the pathname specifies a directory or other
group of files, the server should transfer a list of files
in the specified directory. If the pathname specifies a
file then the server should send current information on the
file. A null argument implies the user's current working or
default directory. ...
NAME LIST (NLST)
This command causes a directory listing to be sent from
server to user site. The pathname should specify a
directory or other system-specific file group descriptor; a
null argument implies the current directory. ...
Per RFC 3659, which defines the MLSD command:
The MLST and MLSD commands each allow a single optional argument.
This argument may be either a directory name or, for MLST only, a
file name. For these purposes, a "file name" is the name of any
entity in the server NVFS which is not a directory. Where TVFS is
supported, any TVFS relative pathname valid in the current working
directory, or any TVFS fully qualified pathname, may be given. If a
directory name is given then MLSD must return a listing of the
contents of the named directory, otherwise it issues a 501 reply, and
does not open a data connection. ...
If no argument is given then MLSD must return a listing of the
contents of the current working directory, and MLST must return a
listing giving information about the current working directory
itself. ...
...
If the Client-FTP sends an invalid argument, the server-FTP MUST
reply with an error code of 501.
*.* and *.zip are not directory names, thus the server will fail if TIdFTP.List() sends an MLSD *.* or MLSD *.zip command. So it stands to reason that TIdFTP.UseMLIS and TIdFTP.CanUseMLS are likely both True in your case (UseMLIS is True by default, and CanUseMLS is commonly True on modern FTP servers).
The MLSD command does not support server-side filtering like the LIST/NLST commands do. So you cannot use things like *.* and *.zip with MLSD. You would have to retrieve the full directory listing and then ignore any entries that you are not interested in. Otherwise, set TIdFTP.UseMLIS to False before calling TIdFTP.List(), but then you run the risk of TIdFTP.DirectoryListing incorrectly parsing the directory listing of some servers, as the format used by the LIST command was never standardized, and there are hundreds of custom formats being used all over the Internet (and why TIdFTP in Indy 10 includes dozens of listing parsers when LIST is used). Unlike MLSx, which has a standardized format (which is why it was introduced in the first place, to replace the shortcomings of LIST).
Thus, what this all comes down to is - when TIdFTP.UseMLIS and TIdFTP.CanUseMLS are both True, ASpecifier MUST be blank or a directory, NOT a file mask.
The TIdFTP.List() documentation does state that List() may internally call TIdFTP.ExtListDir() to send an MLSD command, but it does not specifically mention this particular restriction on the ASpecifier parameter in that case:
If CanUseMLS contains True, the ExtListDir is called to capture and store the results of the FTP MLSD command in the ADest parameter variable instead of the LIST or NLST commands. No additional processing is performed in the List method under this circumstance, and the method is exited.
When ADetails is False, only the file or directory name is returned in the ADest string list using the FTP NLST command. When ADetails is True, List can return FTP server-dependent details including the file size, date modified, and file permissions for the Owner, Group, and User using the FTP LIST command.
The TIdFTP.ExtListDir() documentation does state that its input parameter must be a directory name, though:
The MLSD command, supported in ExtListDir, accepts an optional directory name or relative path in Adirectory for the directory listing. If am empty string is passed in ADirectory, the current directory is used for the directory listing operation.
On a side note: the TIdFTP.DirFormat property will tell you which listing format was detected after TIdFTP.DirectoryListing has parsed the results. Or you can look at the Details and UsedMLS properties of TListFTP.ListResult (type-cast it to TIdFTPListResult to access the properties) to deduce which command was sent by TIdFTP.List() (if successful).
An alternative solution is to include
IdAllFTPListParsers
In your uses clause and to disable UseMLIS.
Like so:
uses
....
IdAllFTPListParsers;
.....
procedure TForm1.DoThis;
var
i: integer;
begin
if not IDFTP1.Connected then IDFTP1.Connect;
IDFTP1.UseMLIS:= false;
IDFTP1.List;
for i:= 0 to IDFTP1.DirectoryListing.Count -1 do begin
.. process directory items.
IdFTP1.TransferType:= ftBinary;
..Get your files

Advantage Table File in use error. How can I resolve?

I'm having trouble getting a certain table to open up in more then one instance of my program.
Whats happening is I'm trying to allow users to open up and replace a current table(part of a data dictionary - FileForm.ImagesTable) with an older table (not included in the data dictionary). It works great for one instance of the program but when we try to open up that same file simultaneously on another instance. I get the following error.
FileName.ADT This file is in use. Enter a new name or close the file that's open in another program.
Below is the code I have reassigning the table name and datapath to the selected table.
OpenDialog1.FileName := '*.adt';
OpenDialog1.Filter := 'Software 6.0 Files (*.adt)|*.adt|Software 5.x Files (*.dbf)|*.dbf';
OpenDialog1.InitialDir := DataPath;
if OpenDialog1.Execute then
begin
Str1 := Trim(OpenDialog1.FileName);
if Length(Str1) = 0 then
Exit;
DSImage.Enabled := False;
with FileForm.ImagesTable do
begin
Active := False;
AfterOpen := FileForm.TableOther.AfterOpen;
DataBaseName := ExtractFilePath(Str1);
TableName := ExtractFileName(Str1);
Active := True;
end;
end;
Edit * Using Advtantage 8.1, Seems to be a windows error because the error happens in the dialogue window. And yes Exclusive is set to false.
Any thougths on why this is happening and how this could be resolved are appreciated.
Thanks
You're not clear on the specific error - is it a Windows error or an Advantage error?
If it's a Windows error, it may be because you've specified exclusive access to the table (ImageTable.Exclusive = True). This would mean that the first instance of the app could open it, but subsequent tries would fail with a File is in use error.
If it's an Advantage error, the Advantage help file (here in v11's documentation, since you didn't specify a version of ADS - note it's in a frame, so you may need to use this link, navigate to Advantage Developers Guide, expand the Part 1->Chapter 4 - Dictionaries->Understanding Dictionaries topic) says:
A data dictionary is a special file that serves as the sole access point for database tables
Note the sole access point. Once a table is in the data dictionary, it belongs to the data dictionary. You're trying to replace that reference with something outside the scope of the dictionary, and that isn't allowed. I'm pretty sure that the problem is related to that - ADS puts a proprietary lock on tables that are included in the dictionary, and controls access to those files through the server by way of the dictionary.
You'll need to either remove the table from the dictionary and use it as a free table, or come up with a different strategy for removing the current data and replacing it with other data to preserve the integrity of the dictionary.
It looks like you are only using the Open Dialog to get the name of the table.
On the Open dialog try setting the option ofShareAware
OpenDialog1.Options := OpenDialog1.Options + [ ofShareAware ];
Once the table is open with Advantage the mode is both deny write, deny read and as a result will return a sharing error if anything non-advantage tries to open the table.

Resources