What exactly are IN, OUT, IN OUT parameters in PL/SQL - oracle

I've looked up questions here as well as looking online and watching videos but I'm still confused exactly what IN, OUT is. The reason I'm asking is because I'm writing a procedure that will log an error based on the IN parameters in other procedures,
Cheers!

The Oracle documentation here does a good job of explaining:
The mode of a parameter indicates whether the parameter passes data to a procedure (IN), returns data from a procedure (OUT), or can do both (IN OUT).
And about OUT parameters specifically:
... you cannot use it to pass a value to the procedure. Nor can you read its value inside the procedure, even after a value has been assigned to it.
EDIT
Actually, though the information provided above is valid, I linked to a poor resource (SQL*Module for Ada Programmer's Guide).
A much better and more complete resource to better understand the 3 modes can be found here: Table 8-1 PL/SQL Subprogram Parameter Modes.
IN mode:
Default mode
Passes a value to the subprogram.
Formal parameter acts like a constant: When the subprogram begins, its value is that of either its actual parameter or default value, and the subprogram cannot change this value.
Actual parameter can be a constant, initialized variable, literal, or expression.
Actual parameter is passed by reference.
OUT mode:
Must be specified.
Returns a value to the invoker.
Formal parameter is initialized to the default value of its type. The default value of the type is NULL except for a record type with a non-NULL default value.
When the subprogram begins, the formal parameter has its initial value regardless of the value of its actual parameter. Oracle recommends that the subprogram assign a value to the formal parameter.
If the default value of the formal parameter type is NULL, then the actual parameter must be a variable whose data type is not defined as NOT NULL.
By default, actual parameter is passed by value; if you specify NOCOPY, it might be passed by reference.
IN OUT mode:
Must be specified.
Passes an initial value to the subprogram and returns an updated value to the invoker.
Formal parameter acts like an initialized variable: When the subprogram begins, its value is that of its actual parameter. Oracle recommends that the subprogram update its value.
Actual parameter must be a variable (typically, it is a string buffer or numeric accumulator).
By default, actual parameter is passed by value (in both directions); if you specify NOCOPY, it might be passed by reference.

Related

Confused about type coercion in function calls (stack frames)

Consider the following example:
create or replace function f(n integer) return integer as
begin
return n;
end;
/
begin
dbms_output.put_line(f(3.8));
end;
/
3.8
PL/SQL procedure successfully completed.
This makes no sense to me. Obviously, PL/SQL simply ignores the integer specification, both on entering the function and on exiting it. Is this simply a bug? Is it a design choice, made deliberately by the language developers?
Here is why I find this confusing. Compare to the following example:
declare
x integer;
begin
x := 3.8;
dbms_output.put_line(x);
end;
/
4
PL/SQL procedure successfully completed.
In this example, the data type specification is complied with. PL/SQL doesn't throw an error, but at least it performs an implicit coercion and it does not violate the data type declared for x - the variable stores the value 4, an integer, not 3.8.
So, how does PL/SQL do the function call thing in the first example? As far as I understand (never having been trained formally in computing), whenever the compiler or interpreter finds a function call it creates a stack frame, with variables for the arguments passed to the function and for the return value to come back from the function. Aren't these variables, when the stack frame is created, supposed to be the same data type as specified in the function declaration? If the stack frame has a field of integer data type for the argument 3.8, how come that is not coerced to 4 before it is even stored in the corresponding variable? And the same thing for the return value: if the function returns 3.8 but the caller expects an integer (and therefore the corresponding variable in the stack frame should be integer), how is it able to accept the return value 3.8?
And, most disturbing - why is this behavior different from the behavior when explicitly declared variables are involved (as in my second example)?
Thank you for sharing your thoughts!
The answer is found in the documentation for Oracle Database (to which your question has absolutely no relation whatsoever).
Firstly, INTEGER in the said database is a synonym for NUMBER(38). Upon assignment to a NUMBER(38) variable x, as in your second example, according to the assignment rules the NUMBER (with arbitrary precision) literal 3.8 is rounded.
In your first example though no assignment happens because IN parameters to PL/SQL subprograms are passed by reference and the same reference (to the NUMBER value 3.8) is returned.

Function with 1/2 values and short variable declaration assigned twice to same variable

I have two questions for following code
emptyinterface.(int) can return one or two values, how the function is defined to achieve that effect?
ok has been declared twice using short variable declaration, why it is possible in this context?
package main
import (
"fmt"
)
func main() {
var emptyinterface interface{}
emptyinterface=4
i1:=emptyinterface.(int)
fmt.Println(i1)
i2,ok:=emptyinterface.(int)//<- how the function is defined such that it can return either 1 (i1) or 2 values (i2,ok)?
fmt.Println(i2,ok)
i3,ok:=emptyinterface.(string) //<--why I can reassign to ok, which has assign previously?
fmt.Println(i3,ok)
}
It's not a function, it's a language feature. You can't write a function that does that, but the compiler writers can create a bit of syntax that does.
A := is invalid if there are no new variables on its left side. If there is at least one new variable being declared, it's allowed.
In each of the cases, there is at-least new variable created along with ok, i.e. i2 and i3, so redeclaration of ok is perfectly fine.
This is well documented in the language spec (emphasis mine) under Short variable declarations
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration.
Also it is unclear, what you are referring as a function here, Type assertion is a feature of the language that asserts if a value within the interface is of a particular type. It always returns the underlying value if the assertion was successful or a failure if its not. You should always be checking the return value of the type assertion (2nd argument) before meaningfully using it elsewhere.

Anonymous struct as pipeline in template

Is there a way to do the following in a html/template?
{{template "mytemplate" struct{Foo1, Foo2 string}{"Bar1", "Bar2"}}}
Actually in the template, like above. Not via a function registered in FuncMap which returns the struct.
I tried it, but Parse panics, see Playground. Maybe just the syntax is wrong?
As noted by others, it's not possible. Templates are parsed at runtime, without the help of the Go compiler. So allowing arbitrary Go syntax would not be feasible (although note that it wouldn't be impossible, as the standard lib contains all the tools to parse Go source text, see packages "prefixed" with go/ in the standard lib). By design philosophy, complex logic should be outside of templates.
Back to your example:
struct{Foo1, Foo2 string}{"Bar1", "Bar2"}
This is a struct composite literal and it is not supported in templates, neither when invoking another template nor at other places.
Invoking another template with a custom "argument" has the following syntax (quoting from text/template: Actions):
{{template "name" pipeline}}
The template with the specified name is executed with dot set
to the value of the pipeline.
TL;DR; A pipeline may be a constant, an expression denoting a field or method of some value (where the method will be called and its return value will be used), it may be a call to some "template-builtin" function or a custom registered function, or a value in a map.
Where Pipeline is:
A pipeline is a possibly chained sequence of "commands". A command is a simple value (argument) or a function or method call, possibly with multiple arguments:
Argument
The result is the value of evaluating the argument.
.Method [Argument...]
The method can be alone or the last element of a chain but,
unlike methods in the middle of a chain, it can take arguments.
The result is the value of calling the method with the
arguments:
dot.Method(Argument1, etc.)
functionName [Argument...]
The result is the value of calling the function associated
with the name:
function(Argument1, etc.)
Functions and function names are described below.
And an Argument is:
An argument is a simple value, denoted by one of the following.
- A boolean, string, character, integer, floating-point, imaginary
or complex constant in Go syntax. These behave like Go's untyped
constants. Note that, as in Go, whether a large integer constant
overflows when assigned or passed to a function can depend on whether
the host machine's ints are 32 or 64 bits.
- The keyword nil, representing an untyped Go nil.
- The character '.' (period):
.
The result is the value of dot.
- A variable name, which is a (possibly empty) alphanumeric string
preceded by a dollar sign, such as
$piOver2
or
$
The result is the value of the variable.
Variables are described below.
- The name of a field of the data, which must be a struct, preceded
by a period, such as
.Field
The result is the value of the field. Field invocations may be
chained:
.Field1.Field2
Fields can also be evaluated on variables, including chaining:
$x.Field1.Field2
- The name of a key of the data, which must be a map, preceded
by a period, such as
.Key
The result is the map element value indexed by the key.
Key invocations may be chained and combined with fields to any
depth:
.Field1.Key1.Field2.Key2
Although the key must be an alphanumeric identifier, unlike with
field names they do not need to start with an upper case letter.
Keys can also be evaluated on variables, including chaining:
$x.key1.key2
- The name of a niladic method of the data, preceded by a period,
such as
.Method
The result is the value of invoking the method with dot as the
receiver, dot.Method(). Such a method must have one return value (of
any type) or two return values, the second of which is an error.
If it has two and the returned error is non-nil, execution terminates
and an error is returned to the caller as the value of Execute.
Method invocations may be chained and combined with fields and keys
to any depth:
.Field1.Key1.Method1.Field2.Key2.Method2
Methods can also be evaluated on variables, including chaining:
$x.Method1.Field
- The name of a niladic function, such as
fun
The result is the value of invoking the function, fun(). The return
types and values behave as in methods. Functions and function
names are described below.
- A parenthesized instance of one the above, for grouping. The result
may be accessed by a field or map key invocation.
print (.F1 arg1) (.F2 arg2)
(.StructValuedMethod "arg").Field
The proper solution would be to register a custom function that constructs the value you want to pass to the template invocation, as you can see in this related / possible duplicate: Golang pass multiple values from template to template?
Another, half solution could be to use the builtin print or printf functions to concatenate the values you want to pass, but that would require to split in the other template.
As mentioned by #icza, this is not possible.
However, you might want to provide a generic dict function to templates to allow to build a map[string]interface{} from a list of arguments. This is explained in this other answer: https://stackoverflow.com/a/18276968/328115

Overloading oracle procedure with DATE and VARCHAR2

I have the following code that doesn't work. It compiles, but when called with sysdate as the parm_value parameter it throws PLS-00307: too many declarations of 'P_UPSERT_SDE_DATA' match this call If I comment out the varchar2 entry, the overload works as expected with just date and number datatypes.
What is the best way to go about what I'm trying to do, which is accept parameters differing only in parm_values datatype(specifically date and varchar2)?
PROCEDURE P_Upsert_SDE_Data(parm_table_name GORSDAV.GORSDAV_TABLE_NAME%TYPE,
parm_attr_name GORSDAV.GORSDAV_ATTR_NAME%TYPE,
parm_key GORSDAV.GORSDAV_PK_PARENTTAB%TYPE,
parm_user_id GORSDAV.GORSDAV_USER_ID%TYPE,
parm_value VARCHAR2);
--
PROCEDURE P_Upsert_SDE_Data(parm_table_name GORSDAV.GORSDAV_TABLE_NAME%TYPE,
parm_attr_name GORSDAV.GORSDAV_ATTR_NAME%TYPE,
parm_key GORSDAV.GORSDAV_PK_PARENTTAB%TYPE,
parm_user_id GORSDAV.GORSDAV_USER_ID%TYPE,
parm_value NUMBER);
PROCEDURE P_Upsert_SDE_Data(parm_table_name GORSDAV.GORSDAV_TABLE_NAME%TYPE,
parm_attr_name GORSDAV.GORSDAV_ATTR_NAME%TYPE,
parm_key GORSDAV.GORSDAV_PK_PARENTTAB%TYPE,
parm_user_id GORSDAV.GORSDAV_USER_ID%TYPE,
parm_value DATE);
You can see this if one of the others arguments you pass is being implicitly converted; from the call you posted I suspect var_FRB‌​GRNT_CODE is a different type and is being converted; e.g. that variable is a number and GORSDAV.GORSDAV_PK_PARENTTAB is a string.
From the documentation:
When trying to determine which subprogram was invoked, if the PL/SQL compiler implicitly converts one parameter to a matching type, then the compiler looks for other parameters that it can implicitly convert to matching types. If there is more than one match, then compile-time error PLS-00307 occurs, as in Example 8-34.
Implicit conversion of one of the other arguments makes it look for potential conversions of the others; it's only then that it sees the date and varchar2 versions, which can be implicitly converted to each other. If all of the arguments are of the same type as the table columns used for the formal parameter declarations then it won't look for implicit conversions, and won't be confused by the date/varchar2 versions.
Whenever I get this error, it seems to be that there's a mismatch between the spec declaration and the body declaration somewhere. Make sure each of your spec declarations match your body declarations exactly.

ReSharper: Find Usages of an optional parameter

If I have a function with optional parameter, is there an easy way to find all the locations in my code that call that function and pass a value to that parameter?
The function has many non-default parameters, so scanning the usual Find Usages results of places that call the function is problematic, as it trims the lines and I can't see if the optional parameter is used.
With your cursor on the parameter, choose ReSharper | Inspect | Value Origin, or from the keyboard, Inspect This with Ctrl+Shift+Alt+A, then Value Origin.
You will get an Inspection Results window with all the places that explicitly assign that parameter a value.
I think the best way is changing Signature of the method. In other word you can change type of the parameter to another type (that is not used by parameters for safety) and see Errors list after rebuild.
By this way you can find all (not only explicitly) usages of the parameter.

Resources