Calling package's procedure from another procedure - stored-procedures

Trying to search but i couldn't find it.
I have a package name package_1 and in that I have multiple procedures/functions. Now I want to call one of these functions from another procedure, which is not part of this package. I can't put this code in that package (both are on same schema).
I am trying this
package_1.function_1(varchar_var_1, varchar_var_2, varchar_var_3);
But it is giving me error.
QUESTION2
The above functions return an object which is a record type defined in package. How can I declare an object of that type in my procedure so that I can assign response in my procedure ?

If the function returns a record type, you'd need to declare a local variable in the caller of that record type. Something like
CREATE OR REPLACE PROCEDURE your_procedure_name( <<parameters>> )
AS
l_rec package_1.record_type;
...
BEGIN
...
l_rec := package_1.function_name( p1, p2, p3 );
...
END;
Of course, this assumes that both the record type and the function are defined in the package spec so that they are public rather than merely being defined as private members of the package that are defined only in the package body.

Check if it is declared in the package header/specification. If it is you
will have access to it.
Function must return a value:
a_value := package_1.function_1(varchar_var_1, varchar_var_2, varchar_var_3);
Check if the package is valid. If it is invalidated then there is not
much you can do (until it is fixed).

Related

How to define an Array of values (or a Column) into a Procedure Argument?

I am working on a Netezza SP and is stuck with a problem.
I have a SP, defined as say:
CREATE OR REPLACE PROCEDURE MY_PROC(VARCHAR(ANY)) RETURNS INTEGER LANGUAGE NZPLSQL
AS
BEGIN_PROC
DECLARE
v_temp ALIAS FOR $1;
/* Other decalarations */
result_ts INTEGER;
BEGIN
result_ts := 0;
/* Procedure Body */
RETURN result_ts;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Exception Raised: %', SQLERRM;
END;
END_PROC;
If I am running this SP with one value, such as:
SELECT MY_PROC('TEST_INPUT');
But if I am trying to run it with a column value, such as:
SELECT MY_PROC(TEST_COLUMN) FROM TEST_TABLE;
Its giving me error as:
ERROR: Can't use a stored procedure in this context
I know that in the second scenario I am passing an Array (i guess) but this is not what the Procedure has expected.
Now I am trying to have a procedure that can accept these kind of values but could not succeeded so far, LOOPing and all I have taken care but only problem is the Argument which I don't know how to pass.
Any help would be appreciated, let me know if I need to provide any extra info on this.
Asif
Stored procedures in Netezza, as of v7.2, can only be called in the following ways, as documented here.
CALL sproc_name(...);
EXEC sproc_name(...);
SELECT sproc_name(...);
Note that the SELECT form does not allow a FROM clause.
If you want the stored procedure to act on a particular column from a particular table that changes from invocation to invocation, you could pass the names of those as arguments to the stored procedure and have the entirety of the SQL logic encoded within. You could even pass arbitrary code into the stored procedure to build a query internally.
The way you are trying to call it now is more like calling a user defined function, and that simply won't work with stored procedures here.

DWScript: How to read a meta class parameter from Delphi side

I'm having trouble using meta classes in DWScript.
We are using scripting to enable VARs and end users to customize our application.
Our application data basically consist of a lot of small objects in a tree structure. Each object can either be "dumb" in that it just displays data or it can be intelligent in some way. The intelligence is implemented with scripting by associating different script classes with the tree objects.
The problem I'm having is that the script needs to communicate to the Delphi side framework what script class it should use to implement the object. Basically I need to pass a script meta class to the Delphi side and store the information there in a format that can be safely persisted (by type name, as a string probably). I also need to be able to go the other way; I.e. return the meta class to the script from the Delphi side.
TdwsUnit declaration
type
// Base class of all tree objects
TItem = class
...
end;
// The meta class
// This is actually declared in code since TdwsUnit doesn't have design time support for meta classes.
// Shown here for readability.
TItemClass = class of TItem;
// The procedure that passes the meta class to the Delphi side.
// I cannot use a TItemClass parameter as that isn't declared until run time (after the TdwsUnit has initialized its tables).
procedure RegisterItemClass(AClass: TClass);
The script
type
TMyItem = class(TItem)
...
end;
begin
// Pass the meta class to the Delphi side.
// The Delphi side will use this to create a script object of the specified type
// and attach it to the Delphi side object.
RegisterItemClass(TMyItem);
end;
Delphi implementation
Declaration of the meta class, TItemClass. Done in TdwsUnit.OnAfterInitUnitTable.
procedure TMyDataModule.dwsUnitMyClassesAfterInitUnitTable(Sender: TObject);
var
ItemClass: TClassSymbol;
MetaClass: TClassOfSymbol;
begin
// Find the base class symbol
ItemClass := dwsUnitMyClasses.Table.FindTypeLocal('TItem') as TClassSymbol;
// Create a meta class symbol
MetaClass := TClassOfSymbol.Create('TItemClass', ItemClass);
dwsUnitMyClasses.Table.AddSymbol(MetaClass);
end;
RegisterItemClass implementation
procedure TMyDataModule.dwsUnitMyClassesFunctionsRegisterItemClassEval(info: TProgramInfo);
var
ItemClassSymbol: TSymbol;
ItemClassName: string;
begin
ItemClassSymbol := TSymbol(Info.Params[0].ValueAsInteger);
ItemClassName := ItemClassSymbol.Name;
...
end;
So the question is How does one get a TSymbol from a meta class parameter?
Edit: I found the answer to one part of the problem in this old question.
In short the solution is to cast the parameter value to a TSymbol:
However...
Now assuming that I store the class name as a string. How do I get from this class name back to a symbol? I need this because, just as the script can set the item class (using the code above), the script can also ask for an items' class.
I have tried looking in the symbol table with any of the four different methods that seem to do what I need but none of them can find the symbol.
var
ItemClassName: string;
ItemClassSymbol: TSymbol;
...
ItemClassName := 'TMyItem';
...
ItemClassSymbol := Info.Table.FindTypeSymbol(ItemClassName, cvMagic);
if (ItemClassSymbol = nil) then
ItemClassSymbol := Info.Table.FindSymbol(ItemClassName, cvMagic);
if (ItemClassSymbol = nil) then
ItemClassSymbol := Info.Table.FindTypeLocal(ItemClassName);
if (ItemClassSymbol = nil) then
ItemClassSymbol := Info.Table.FindLocal(ItemClassName);
// ItemClassSymbol is nil at this point :-(
So the question is Given the name of meta class, declared in script, how does one get the corresponding TSymbol from the Delphi side?
Edit: I have now found one possible solution to the last part.
The following seems to work but I'm unsure if that is the correct way to do it. I would have thought that I would need to limit the scope of the symbol search to the current script unit.
var
ItemClassName: string;
ItemClassSymbol: TSymbol;
...
ItemClassName := 'TMyItem';
...
ItemClassSymbol := Info.Execution.Prog.RootTable.FindSymbol(ItemClassName, cvMagic);
if (ItemClassSymbol = nil) then
raise EScriptException.CreateFmt('ItemClass not found: %s', [ItemClassName]);
Info.ResultAsInteger := Int64(ItemClassSymbol);
Unless I misundertood, you probably shouldn't be looking up the symbol table for your last part, but instead maintain a table of the registered item classes in dwsUnitMyClassesFunctionsRegisterItemClassEval.
The rationale behind that could be that the user could have two 'TMyItem' symbols, in two different contexts, but only one registered. The registered one is the one you want, and I don't think there is a reliable way to figure out the relevant symbol otherwise (as the context that matter wouldn't be the one where you're trying to resolve the string back to a symbol, but the one where the symbol & string were associated, ie. where it was registered)

Delphi trouble: Sorting a Tobjectlist<>

I want to sort my generic tobjectlist using the built-in sort method.
here is what I do:
//create the list object
myList := TObjectList<MyType>.Create(false);
[...] //populate the list with unsorted entries
//sort the list
myList.sort(#Comparer);
[...]//store sorted results back to array
myList.Destroy;
my Comparer function looks like this:
function Comparer(Item1, Item2 : pointer):integer;
begin
result := myCompare(item1, item2);
end;
According to the specs, it should work like this.
I get an compiler error E2250 No overloaded version of 'Sort' exist with these parameters (exact wording differs, i use a non english version of RAD Studio)
I have no idea why this should not be valid Pascal - does anyone of you have insight to share on this?
You are almost there. Since I don't know what MyType is you may need to change the call to your myCompare function.
myList.Sort(TComparer<MyType>.Construct(
function (const L, R: MyType): integer
begin
result := myCompare(L, R);
end
));
TObjectList<T>.Sort is declared as:
procedure Sort(const AComparer: IComparer<T>);
IComparer<T> is defined as:
IComparer<T> = interface
function Compare(const Left, Right: T): Integer;
end;
You are instantiating TObjectList<MyType> and so you need to pass an IComparer<MyType> to Sort. In order to do this you will need an object to provide a concrete implementation of that interface.
One obvious way to do this would be to subclass TObjectList<MyType> and implement the interface there.
Another way to do this is to use TComparer<T> to create an IComparer<T> on demand using its Construct class function. You would need to supply a comparison function:
TComparison<T> = reference to function(const Left, Right: T): Integer;
Leonardo's answer demonstrates how to do this.
If the compiler says no overloaded version exists with that parameter type, ask yourself what overloads do exist. Check the source code or the documentation to find out.
There you'll see that TObjectList<T> inherits two Sort methods from TList<T>. One takes no arguments, and the other takes a reference to something implementing the IComparer<T> interface. Your standalone function doesn't fit that. Write a descendant of TComparer<MyType> and override its Compare method.

need help with interesting call to JCL's TEvaluator

i'm using JCL's expression evaluator TEvaluator (a marvelous creation donated by barry kelly). (THANK YOU barry!)
background
i've used the AddFunc method.
function MyFunc:double;
begin
// calculations here
Result:=1;
end;
you can use the AddFunc method to make the function available:
AddFunc('MyFunc', MyFunc);
here's the problem...
i need to call a method on an object instead of a standalone routine.
the reason is that i have a list of objects that provide the values.
say we have a list of vehicle objects. each object has a Weight function. i want to be able to make available each object's weight available for use in the formula.
a silly example but it's easy to explain:
type
TVehicle=class
private
public
function Weight:double;
end;
function StrangeCalculation:double;
var
vehicle:TVehicle;
begin
for iVehicle = 0 to Count - 1 do
begin
vehicle:=GetVehicle(iVehicle);
// E2250 There is no overloaded version of 'AddFunc' that can be called with these arguments
eval.AddFunc(vehicle.Name, vehicle.Weight);
end;
Result:=eval.Evaluate('JeepTJWeight + FordF150Weight * 2');
end;
my options:
AddVar( ) or AddConst( ) -- but that isn't so great because i need to be able to raise an exception if the value is not available.
AddFunc( ) with standalone functions. can't do that because the names of (and number of) variables is unknown until runtime.
modify the object to add a callback if the variable isn't found. i have actually done this but needed to edit a copy of the source to call back to make it do this.
make an AddFunc( ) that's able to use method functions.
option #3 is actually built but an additional AddFunc would be nicer. the trouble is i don't know what method prototype to provide. i thought TMethod would be the way but my knowledge is too limited here... here was my unsuccessful attempt but i still get "E2250 There is no overloaded version of 'AddFunc' that can be called with these arguments" at the eval.AddFunc() call like before.
TFloat64MethodFunc = function(c:pointer): TFloat64;
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TFloat64MethodFunc);
begin
FOwnContext.Add(TExprFloat64MethodFuncSym.Create(AName, AFunc));
end;
TExprFloat64MethodFuncSym = class(TExprAbstractFuncSym)
private
FFunc: TFloat64MethodFunc;
public
constructor Create(const AIdent: string; AFunc: TFloat64MethodFunc);
function Evaluate: TFloat; override;
// not using function Compile: TExprNode; override;
end;
thank you for your help!
mp
figured it out...
TFloat64MethodFunc = function: TFloat of object;
Long time ago (2004), I have faced this problem. My solution then was to use the Turbo Power SysTools evaluator, that accepts methods.

How to know what type is a var?

TypeInfo(Type) returns the info about the specified type, is there any way to know the typeinfo of a var?
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= TypeInfo(S);
Info:= TypeInfo(Instance);
Info:= TypeInfo(Obj);
end
This code returns:
[DCC Error] Unit1.pas(354): E2133 TYPEINFO standard function expects a type identifier
I know a non instantiated var is only a pointer address.
At compile time, the compiler parses and do the type safety check.
At run time, is there any way to know a little more about a var, only passing its address?
No.
First, there's no such thing as a "non-instantiated variable." You instantiate it by the mere act of typing its name and type into your source file.
Second, you already know all there is to know about a variable by looking at it in your source code. The variable ceases to exist once your program is compiled. After that, it's all just bits.
A pointer only has a type at compile time. At run time, everything that can be done to that address has already been determined. The compiler checks for that, as you already noted. Checking the type of a variable at run time is only useful in languages where a variable's type could change, as in dynamic languages. The closest Delphi comes to that is with its Variant type. The type of the variable is always Variant, but you can store many types of values in it. To find out what it holds, you can use the VarType function.
Any time you could want to use TypeInfo to get the type information of the type associated with a variable, you can also directly name the type you're interested in; if the variable is in scope, then you can go find its declaration and use the declared type in your call to TypeInfo.
If you want to pass an arbitrary address to a function and have that function discover the type information for itself, you're out of luck. You will instead need to pass the PTypeInfo value as an additional parameter. That's what all the built-in Delphi functions do. For example, when you call New on a pointer variable, the compiler inserts an additional parameter that holds the PTypeInfo value for the type you're allocating. When you call SetLength on a dynamic array, the compiler inserts a PTypeInfo value for the array type.
The answer that you gave suggests that you're looking for something other than what you asked for. Given your question, I thought you were looking for a hypothetical function that could satisfy this code:
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= GetVariableTypeInfo(#S);
Assert(Info = TypeInfo(string));
Info:= GetVariableTypeInfo(#Instance);
Assert(Info = TypeInfo(IObjectType));
Info:= GetVariableTypeInfo(#Obj);
Assert(Info = TypeInfo(TDBGrid));
end;
Let's use the IsClass and IsObject functions from the JCL to build that function:
function GetVariableTypeInfo(pvar: Pointer): PTypeInfo;
begin
if not Assigned(pvar) then
Result := nil
else if IsClass(PPointer(pvar)^) then
Result := PClass(pvar).ClassInfo
else if IsObject(PPointer(pvar)^) then
Result := PObject(pvar).ClassInfo
else
raise EUnknownResult.Create;
end;
It obviously won't work for S or Instance above, but let's see what happens with Obj:
Info := GetVariableTypeInfo(#Obj);
That should give an access violation. Obj has no value, so IsClass and IsObject both will be reading an unspecified memory address, probably not one that belongs to your process. You asked for a routine that would use a variable's address as its input, but the mere address isn't enough.
Now let's take a closer look at how IsClass and IsObject really behave. Those functions take an arbitrary value and check whether the value looks like it might be a value of the given kind, either object (instance) or class. Use it like this:
// This code will yield no assertion failures.
var
p: Pointer;
o: TObject;
a: array of Integer;
begin
p := TDBGrid;
Assert(IsClass(p));
p := TForm.Create(nil);
Assert(IsObject(p));
// So far, so good. Works just as expected.
// Now things get interesting:
Pointer(a) := p;
Assert(IsObject(a));
Pointer(a) := nil;
// A dynamic array is an object? Hmm.
o := nil;
try
IsObject(o);
Assert(False);
except
on e: TObject do
Assert(e is EAccessViolation);
end;
// The variable is clearly a TObject, but since it
// doesn't hold a reference to an object, IsObject
// can't check whether its class field looks like
// a valid class reference.
end;
Notice that the functions tell you nothing about the variables, only about the values they hold. I wouldn't really consider those functions, then, to answer the question of how to get type information about a variable.
Furthermore, you said that all you know about the variable is its address. The functions you found do not take the address of a variable. They take the value of a variable. Here's a demonstration:
var
c: TClass;
begin
c := TDBGrid;
Assert(IsClass(c));
Assert(not IsClass(#c)); // Address of variable
Assert(IsObject(#c)); // Address of variable is an object?
end;
You might object to how I'm abusing these functions by passing what's obviously garbage into them. But I think that's the only way it makes sense to talk about this topic. If you know you'll never have garbage values, then you don't need the function you're asking for anyway because you already know enough about your program to use real types for your variables.
Overall, you're asking the wrong question. Instead of asking how you determine the type of a variable or the type of a value in memory, you should be asking how you got yourself into the position where you don't already know the types of your variables and your data.
With generics, it is now possible to get the type info without specifying it.
Certain users indicated the following code doesn't compile without errors.
As of Delphi 10 Seattle, version 23.0.20618.2753, it compiles without errors, as seen below in the screenshot.
program TypeInfos;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.TypInfo;
type
TTypeInfo = class
class procedure ShowTypeInfo<T>(const X: T);
end;
{ TTypeInfo }
class procedure TTypeInfo.ShowTypeInfo<T>(const X: T);
var
LTypeInfo: PTypeInfo;
begin
LTypeInfo := TypeInfo(T);
WriteLn(LTypeInfo.Name);
end;
var
L: Exception;
B: Boolean;
begin
// Console output
TTypeInfo.ShowTypeInfo(L); // Exception
TTypeInfo.ShowTypeInfo(B); // Boolean
end.
Not that I know of. You can get RTTI (Run Time Type Information) on published properties of a class, but not for "normal" variables like strings and integers and so forth. The information is simply not there.
Besides, the only way you could pass a var without passing a type is to use either a generic TObject parameter, a generic type (D2008, as in ), or as an untyped parameter. I can't think of another way of passing it that would even compile.

Resources