Reputation: 3
I'm trying to make a modification to an existing PL/SQL package I coded some time ago. The original block in question looked like this (which worked fine)
FUNCTION GEN_COLUMN_TYPE ( DTYPE IN VARCHAR2, --DATATYPE OF THE COLUMN
PRCISION IN NUMBER, --PRECISION OF THE COLUMN
SCLE IN NUMBER, --PRECISION OF THE COLUMN
DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
APP_CODE IN VARCHAR2 -- DATABASE TYPE
)RETURN STRING IS
V_COLUMNTYPE STRING(40) := NULL;
BEGIN
V_COLUMNTYPE := DTYPE;
BEGIN
SELECT TARGET_DATATYPE INTO V_COLUMNTYPE FROM DDL_DATATYPE_MAP DDM
INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
AND DSA.APPLICATION_CODE=APP_CODE
WHERE DDM.SOURCE_DATATYPE=DTYPE;
END;
I have modified it now to look like this. The only change I made was adding the 2 new variables into the definition and the "SELECT INTO" statement so I could use them based on the same join criteria later in the code.
FUNCTION GEN_COLUMN_TYPE ( DTYPE IN VARCHAR2, --DATATYPE OF THE COLUMN
PRCISION IN NUMBER, --PRECISION OF THE COLUMN
SCLE IN NUMBER, --PRECISION OF THE COLUMN
DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
APP_CODE IN VARCHAR2, --APPLICATION CODE
DBMS_TYPE VARCHAR2, --DATABASE TYPE
VAR_LENGTH_IND VARCHAR2 --WHETHER THE FIELD NEEDS PARENS OR NOT
)RETURN STRING IS
V_COLUMNTYPE VARCHAR2(40) := NULL;
BEGIN
V_COLUMNTYPE := DTYPE;
BEGIN
SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND INTO V_COLUMNTYPE, DBMS_TYPE, VAR_LENGTH_IND FROM DDL_DATATYPE_MAP DDM
INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
AND DSA.APPLICATION_CODE=APP_CODE
WHERE DDM.SOURCE_DATATYPE=DTYPE;
END;
And I'm getting the all-too-common "PL-00382: expression is of wrong type" on the "SELECT ... INTO" statement at the end. All three variables and columns datatypes are varchar2. I've poured over this and can't see anything wrong. What am I missing?
Edit: Sharing this attempt to use local variables and rewrote the naming for more readability. However I am getting an error on "'V_DBMS_TYPE' must be declared"
FUNCTION GEN_COLUMN_TYPE ( P_DTYPE IN VARCHAR2, --DATATYPE OF THE COLUMN
P_PRCISION IN NUMBER, --PRECISION OF THE COLUMN
P_SCLE IN NUMBER, --PRECISION OF THE COLUMN
P_DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
P_CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
P_APP_CODE IN VARCHAR2
)RETURN STRING IS
V_COLUMNTYPE VARCHAR2(40) := NULL;
BEGIN
V_COLUMNTYPE := P_DTYPE;
DECLARE
V_DBMS_TYPE VARCHAR2(30) := NULL; --DATABASE TYPE
V_VAR_LENGTH_IND VARCHAR2(30) := NULL; --WHETHER THE FIELD NEEDS PARENS OR NOT
BEGIN
SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND INTO V_COLUMNTYPE, V_DBMS_TYPE, V_VAR_LENGTH_IND FROM DDL_DATATYPE_MAP DDM
INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND DDM.SOURCE_DBMS=DSA.SOURCE_DBMS
AND DSA.APPLICATION_CODE=P_APP_CODE
WHERE DDM.SOURCE_DATATYPE=P_DTYPE;
Upvotes: 0
Views: 603
Reputation: 231881
You added two parameters to your function. You don't specify a parameter mode (IN
, OUT
, or IN OUT
) so the default is IN
. An IN
parameter cannot be the target of a SELECT INTO
because the parameter is read-only inside the function.
It is not clear to me whether you really wanted to declare two new local variables, rather than two additional parameters, or whether you really want to declare the two new parameters to be OUT
or IN OUT
parameters. If you declare the parameters as OUT
or IN OUT
, they could be the target of an assignment. But your function would no longer be callable from SQL. If you declare two new local variables, the function would still be callable from SQL but you would not be able to pass in (or be passed back) the values that you gather from your SELECT
statement.
As a general suggestion, I would much prefer to see a common naming convention used to differentiate parameters from local variables and from column names-- that makes reading the code much easier. If your parameters, for example, used a standard P_
prefix, it would be immediately clear in your SELECT
statement that some of your targets were local variables and some were parameters.
Based on the comments, you want to declare additional local variables rather than adding parameters. That would look something like
CREATE OR REPLACE FUNCTION GEN_COLUMN_TYPE (
DTYPE IN VARCHAR2, --DATATYPE OF THE COLUMN
PRCISION IN NUMBER, --PRECISION OF THE COLUMN
SCLE IN NUMBER, --PRECISION OF THE COLUMN
DATA_LENGTH IN NUMBER, --DATA LENGTH OF THE COLUMN
CHAR_LENGTH IN NUMBER, --CHARACTER LENGTH OF THE COLUMN
APP_CODE IN VARCHAR2 --APPLICATION CODE
)
RETURN VARCHAR2
IS
V_DBMS_TYPE VARCHAR2(100); --DATABASE TYPE
V_VAR_LENGTH_IND VARCHAR2(100); --WHETHER THE FIELD NEEDS PARENS OR NOT
V_COLUMNTYPE VARCHAR2(40) := NULL;
BEGIN
V_COLUMNTYPE := DTYPE;
SELECT TARGET_DATATYPE, SOURCE_DBMS, TARGET_VARIABLE_LEN_IND
INTO V_COLUMNTYPE, V_DBMS_TYPE, V_VAR_LENGTH_IND
FROM DDL_DATATYPE_MAP DDM
INNER JOIN DDL_SOURCE_APPLICATION DSA ON DDM.TARGET_DBMS=DSA.TARGET_DBMS AND
DDM.SOURCE_DBMS=DSA.SOURCE_DBMS AND
DSA.APPLICATION_CODE=APP_CODE
WHERE DDM.SOURCE_DATATYPE=DTYPE;
<<more code>>
END;
Upvotes: 3