jooq generates not compiled code from Postgres procedures - stored-procedures

Now I am trying to use JOOQ in new version of program that communicate with 2 DBs simultaneously. But problem is coming from Postgres procedures which I cant deactivate cause of Routine generation cannot be deactivated, even if I don't need them in my program.
Problem 1
Jooq understand some procedures like a tables. I am not pro with SQL so I don't know why this happens, maybe cause of procedure return type? Code for generate one of procedures that have this "bug":
CREATE OR REPLACE FUNCTION dblink_get_notify(IN conname text, OUT notify_name text, OUT be_pid integer, OUT extra text)
RETURNS SETOF record AS
'$libdir/dblink', 'dblink_get_notify'
LANGUAGE c VOLATILE STRICT
COST 1
ROWS 1000;
ALTER FUNCTION dblink_get_notify(text)
OWNER TO postgres;
Maybe cause of problem is fact that there is another procedure with the same name, but without IN parameter:
CREATE OR REPLACE FUNCTION dblink_get_notify(OUT notify_name text, OUT be_pid integer, OUT extra text)
RETURNS SETOF record AS
'$libdir/dblink', 'dblink_get_notify'
LANGUAGE c VOLATILE STRICT
COST 1
ROWS 1000;
ALTER FUNCTION dblink_get_notify()
OWNER TO postgres;
Problem 2
Some generated classes from procedures have compile errors (procedure above have this bug too )
I will give you another example:
CREATE OR REPLACE FUNCTION bt_page_stats(IN relname text, IN blkno integer, OUT blkno integer, OUT type "char", OUT live_items integer,
OUT dead_items integer, OUT avg_item_size integer, OUT page_size integer, OUT free_size integer, OUT btpo_prev integer,
OUT btpo_next integer, OUT btpo integer, OUT btpo_flags integer)
RETURNS record AS '$libdir/pageinspect', 'bt_page_stats'
LANGUAGE c VOLATILE STRICT
COST 1;
ALTER FUNCTION bt_page_stats(text, integer)
OWNER TO postgres;
JOOQ understands this procedure as a routine. But generated code have identical twice Parameter<Integer> BLKNO field. And what I found strange is constructor of that class:
/**
* Create a new routine call instance
*/
public BtPageStats() {
super("bt_page_stats", Public.PUBLIC);
addInParameter(RELNAME);
addInOutParameter(BLKNO);
addInOutParameter(BLKNO);
addOutParameter(TYPE);
addOutParameter(LIVE_ITEMS);
addOutParameter(DEAD_ITEMS);
addOutParameter(AVG_ITEM_SIZE);
addOutParameter(PAGE_SIZE);
addOutParameter(FREE_SIZE);
addOutParameter(BTPO_PREV);
addOutParameter(BTPO_NEXT);
addOutParameter(BTPO);
addOutParameter(BTPO_FLAGS);
}
Look at double addOutParameter(BLKNO)!
Wooh, think thats all. Hope you can help me with that problems :)

You ran into bug #4055. As of jOOQ 3.6, overloaded table-valued functions generate code that doesn't compile.
But problem is coming from Postgres procedures which I cant deactivate cause of Routine generation cannot be deactivated, even if I don't need them in my program.
That's true, but you can exclude them from the code generator explicitly by name, e.g. by specifying:
<excludes>dblink_get_notify|bt_page_stats</excludes>
More info about the code generator configuration can be found here

Related

SAP HANA Stored Procedure optional output parameter with text type

Let's imagine that I have created the stored procedure in SAP HANA database and would like to have optional out parameter with text type, like error details. As I have read to achieve this I should use some default value thus I have done like this:
PROCEDURE "myProcedure"
(
IN inSomeParameter BIGINT,
OUT outResult INTEGER, -- output, result of the operation
OUT outErrorDetail NVARCHAR(32) default ''
)
Unfortunately build failed with the following error:
OUT and IN OUT parameters may not have default expressions
So, I decided to try with null, but it failed the same way. Later I changed the type to integer just to try and it failed exactly same way again.
In the same time this works:
PROCEDURE "myProcedure"
(
IN inSomeParameter BIGINT,
OUT outResult INTEGER, -- output, result of the operation
OUT outErrorDetail TABLE(errorDetails NVARCHAR(32)) default empty
)
but it feels like a huge overkill - to make a table to return only one text value.
Do you have any suggestion how to add optional output parameter?
SQL Script in its current state doesn’t allow for optional OUT parameters.
Why don’t you just set the OUT parameter default value in the procedure body right before the code?
This adds boilerplate code, but you could also use it to convey explicit success messages.

How to use a temporary table with dynamic sql?

Im want to use a temporary table with dynamic sql but i have an error saying that the column Column, parameter, or variable #3: Cannot find data type MyTable. Must declare the table variable "#CountriesFound".
Here's my code
ALTER PROCEDURE sqlDynamic #countryId int
AS
CREATE TYPE MyTable AS TABLE ([countries] varchar(50));
DECLARE #statement NVARCHAR(MAX)
DECLARE #CountriesFound AS MyTable
INSERT INTO #CountriesFound(countries)
select Name
FROM CountriesFound
SET #statement =
'SELECT name, CASE WHEN (c.name IN (SELECT countries FROM #CountriesFound)) THEN 1
ELSE 0
END as countryFound FROM Country c WHERE c.countryId = #countryId'
EXECUTE sp_executesql #statement,
N'#countryId int, #CountriesFound MyTable READONLY',
#countryId = #countryId,
#CountriesFound=#CountriesFound;
Any idea how to fix it ?
The error you are getting has nothing to do with dynamic sql. You cannot create a stored procedure that uses a User-Defined DataType (MyTable in your example) in the same procedure that is going to create the TYPE. The TYPE has to already be created before the procedure will even let the code compile.
Consider this simplified code:
CREATE PROCEDURE TypeTest
AS
CREATE TYPE MyTable AS TABLE ([Id] int);
DECLARE #mt AS MyTable;
Just executing this will give the error:
Msg 2715, Level 16, State 3, Procedure TypeTest, Line 1 Column,
parameter, or variable #1: Cannot find data type MyTable. Parameter or
variable '#mt' has an invalid data type.
You need to CREATE the TYPE outside of the procedure code before you try to create the procedure. It doesn't make sense to CREATE a TYPE inside a procedure code, since TYPE objects are permanent on the server until they are dropped anyway, and procedures are usually created to be run multiple times.
It would be nice if the SQL Server gave an error message more to this effect, but SQL Server isn't famous for having the most helpful error messages.

What is the Delphi equivalent for LPLONG?

I have to access several functions of a DLL written in c from Delphi (currently Delphi7).
I can do it without problems when the parameters are scalar
(thanks to the examples found in this great site!), but I have been stuck for some time when in the parameters there is a pointer to an array of Longs.
This is the definition in the header file of one of the functions:
BOOL __stdcall BdcValida (HANDLE h, LPLONG opcl);
(opcl is an array of longs)
And this is a portion of my Delphi code:
type
TListaOpciones= array of LongInt; //I tried with static array too!
Popcion = ^LongInt; //tried with integer, Cardinal, word...
var
dllFunction: function(h:tHandle; opciones:Popcion):boolean;stdcall;
arrayOPciones:TListaOpciones;
resultado:boolean;
begin
.....
I give values ​​to aHandle and array arrayOPciones
.....
resultado:=dllFunction(aHandle, #arrayopciones[0]);
end;
The error message when executing it is:
"Project xxx raised too many consecutive exceptions: access violation
at 0x000 .."
What is the equivalent in Delhpi for LPLONG? Or am I calling the function in an incorrect way?
Thank you!
LONG maps to Longint, and LPLONG maps to ^Longint. So, you have translated that type correctly.
You have translated BOOL incorrectly though. It should be BOOL or LongBool in Delphi. You can use either, the former is an alias for the latter.
Your error lies in code or detail we can't see. Perhaps you didn't allocate an array. Perhaps the array is incorrectly sized. Perhaps the handle is not valid. Perhaps earlier calls to the DLL failed to check for errors.

Script always throws an error if CREATE/ALTER is not first statement

I am getting an error when I try to execute the script that is given at end of this post. My requirement is to check for procedure's existence, then drop it if it exists and finally create the procedure.
How would I do this using a single script file?
Procedure Proc_GenerateTestData. 'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. SQL2.sql 12 1
The SQL script that always throws above error is as below.
IF OBJECT_ID('dbo.Proc_GenerateTestData', 'p') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.Proc_GenerateTestData
END
CREATE PROCEDURE dbo.Proc_GenerateTestData #numberOfRecords INT = 100
AS
--drop table #temp1
DECLARE #currentTime AS TIME = CAST(GETDATE() AS TIME);
DECLARE #currentWorkShiftDate AS DATETIME = CAST(CAST(GETDATE() AS DATE) AS DATETIME);
DECLARE #startTime TIME,
#lastShiftStartTime TIME;
DECLARE #tenantId AS UNIQUEIDENTIFIER = (SELECT TOP (1)
Tenants.Id
FROM Tenants
ORDER BY Tenants.Id ASC);
DECLARE #workshiftId INT,
#lastShiftStartDate DATETIME;
--more statements for this procedure follow
As the error clearly says - the CREATE PROCEDURE must be the first statement in a query batch.
This is not the case here, since you have the check for the DROP before hand.
You need to change your script so that the CREATE PROCEDURE statement is really the first in the query batch. If you're running this in SQL Server Management Studio, just add a GO delimiter before the CREATE.

Delphi DLL-use functions designed to return a set of values Integer Record

Currently need to use Delphi to write a DLL, so that the main program calls to the specified place in the removable disk in a file,
Main program designed to VC + +, so use Strut way to call the DLL's data as round!!
Current problems encountered when the main program calls my DLL, the incoming group A Record, and other functions has been dealt with, to return the group B Record,
But using Delphi written DLL, can receive group A Record, but returned group B, but always errors!!
The following is the code for the DLL function, would like to ask if anyone encountered such problems can help point to mention turned a deaf ear
Thanks! !
enter code here
library usbdll;
uses
Windows,
SysUtils,
Classes;
{$R *.res}
Type
p_fin=^TSfin;
TSfin = record //A group of Record is the main program calls incoming Record Type
ST_act:Integer;
pathlen:Integer;//Pass true path length, so that I can get to the far left pathlen, then to remove the rear garbled
Id_hand:Integer;
Id_tail:Integer;
path: PWideChar://The reason why the file path Pwidechar do use guidelines because another branch dll is passed to the main program main program <file path + unicode>, is behind the path and dragging a bunch of gibberish characters
Type
p_out=^TRfout;//B Record is set to return to the main program of the Record Type
TRfout= Record
ST_act:Integer;
ST_move:Integer;
Revis:Integer;
Crchk:Integer;
end;
//The following is my comment out.
// The use of the test in two ways, directly back to the group B Record, does not receive group A Record,A group that does not receive Record, when the main program a call, immediately return the relevant data, the results are normal.
(*
function RFoutEt(test:p_out):Boolean;stdcall; //ok Function writing mode
begin
test^.ST_act:=14;
test^.ST_move:=10;
test^.Revis:=12;
test^.Crchk:=8;end;exports RFoutEt;
procedure RFoutE(out Result:TRfout);cdecl; //ok Procedure writing mode
begin
Result.ST_act:=14;
Result.ST_move:=10;
Result.Revis:=12;
Result.Crchk:=8;end;exports RFoutEt;
*)
// Actually, I need to charge the main program to my group A Record datain order to deal with post-op, get really want to move the file to specify the true path,and ultimately return to group B Record.
function RFoutE(ap_sendin:p_fin;num:Integer):TRfout;stdcall; //error
var
str_tmp,str_tmp2,temi_diry:string;
i,copyNum:Integer;
arr: array[0..100] of Char;
begin
//Program by adding the following {} after paragraph, Result is not an empty value is displayed to access illegal address,causing abnormal program termination.
{
StrCopy(arr,Pchar(ap_sendin^.path));
repeat
str_tmp:=temi_diry;//Use the file path string char array A group referred to in the PWidechar removed
str_tmp2:=arr[i];
Inc(i);
until i>=ap_sendin.pathlen;
copyNum:=Prs_Filecopy(temi_diry;ap_sendin^.path);//A group of Record with associated data to complete the move of the specified file
}
Result.ST_act:=4;//The following four lines of words alone are able to return data
Result.ST_move:=0;
Result.Revis:=2;
Result.Crchk:=copyNum;end;
PS. Following is a test using VC + + to try more than one function is normal demand
struct Sfin{
int ST_act;
int pathlen;
int Id_hand;
int Id_tail;
wchar_t *path;
};
struct Rfout{
int ST_act;
int ST_move;
int Revis;
int Crchk;
};
Rfout RFoutE(struct Sfin *a, int num)
{
int ret = 1;
Rfout OutStruct;
copyNum = Prs_Filecopy(temi_diry, inAnow, Anow->path);
ret=1;
if(ret==1){
OutStruct.ST_act =14;
OutStruct.ST_move =10;
OutStruct.Revis = 12;
OutStruct.Crchk = 8;
Anow = freeA(Anow);
}
return OutStruct;
}
There is no standard ABI for larger than machine word sized return values. And Delphi uses a different ABI from any other compiler that I've encountered so you'll have no luck returning large records that way.
You'll need to return the record as an out parameter rather than a function return value. Once you make that change, all will be well.
It also looks like your C++ functions use cdecl rather than stdcall.

Resources