USQL create user defined table type with user defined data type columns - azure-data-lake

I defined a User Defined Type as
namespace AddOns{
[SqlUserDefinedType(typeof(JsonObjectFormatter))]
public class JsonObject
{
public string Value {get;set;}
... // this is just a dummy representation
}
}
I want to define a Table Valued Function that returns a datatype
REFERENCE ASSEMBLY [AddOns];
CREATE TYPE Insight.dbo.JsonRow
AS TABLE
(
[Id] Guid,
[Value] AddOns.JsonObject
);
However I get an error
'E_CSC_USER_INVALIDCOLUMNTYPE: 'AddOns.JsonObject' cannot be used as column type.
Description:
The column type must be a supported scalar, complex or user defined type.
Resolution:
Ensure the column type is a supported type. For a user defined type, make sure the type is registered, the type name is fully qualified, and the required assembly is referenced by the script.'
*** Compile failed !
I have registered the appropriate DLL in my local instance of ADLA and I am able to access the type in the procedures SELECT statements when I am persisting the data to a file. But cannot return it as a TVF return type

You are limited to only the built in types when creating a custom type. From the MS documentation page (the literal last line I pasted says only built in types):
U-SQL can name and register table types with the CREATE TYPE statement.
Create_Type_Statement :=
'CREATE' 'TYPE' ['IF' 'NOT' 'EXISTS'] Type_Identifier
'AS' Anonymous_Table_Type.
Type_Identifier :=
DB_Object_Identifier.
Anonymous_Table_Type :=
'TABLE' '(' Column_Definition_List ')'.
Semantics of Syntax Elements
...
Column_Definition_List
Defines the table schema as follows :
Column_Definition_List :=
Column_Definition { ',' Column_Definition }.
Column_Definition
A column definition is of the form
Column_Definition :=
Quoted_or_Unquoted_Identifier Built_in_Type.

Related

Pass inline declared table/variable to subroutine in ABAP

I know when I need to pass an internal table to a subroutine, I need to declare a type so I can use it in the FORM statement.
What happens if the internal table is an inline declaration table from a SELECT statement like this:
SELECT * FROM KNA1 INTO TABLE #DATA(LT_KNA1)
Is there any way to pass this table to a subroutine?
Thank you.
The subroutines are obsolete since ABAP 7.02 (2009), so I use a method in my example.
Inline declarations are an easy way of declaring types implicitly, but the limit of this solution is that you can type the parameter of a method only generically (types STANDARD TABLE, INDEX TABLE, ANY TABLE, ANY) which prevents you from stating the component names statically in your code.
But inline declarations of type DATA(...) are always based on a complete "bound" data type, so you can declare the type explicitly with TYPES and use it to type both your parameter and your data object.
If you use the ABAP Development Tools (Eclipse), you may use the Quick Fix "Declare local variable ... explicitly" to simplify the task:
which gives this code:
REPORT.
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD main.
TYPES: BEGIN OF helper_type, " <=== automatically generated
carrid TYPE scarr-carrid,
carrname TYPE scarr-carrname,
END OF helper_type.
DATA: lt_scarr TYPE STANDARD TABLE OF helper_type. " <=== automatically generated
SELECT carrid, carrname FROM scarr
INTO TABLE #lt_scarr. " <=== automatically changed
ENDMETHOD.
ENDCLASS.
Now, declare manually the table type, use it to type a parameter of a method (a new one here):
REPORT.
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF helper_type,
carrid TYPE scarr-carrid,
carrname TYPE scarr-carrname,
END OF helper_type.
TYPES: tt_scarr TYPE STANDARD TABLE OF helper_type. " <=== declare the type
CLASS-METHODS main.
CLASS-METHODS process_table " <=== new method with this type
IMPORTING table TYPE tt_scarr.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD main.
DATA: lt_scarr TYPE STANDARD TABLE OF helper_type.
SELECT carrid, carrname FROM scarr
INTO TABLE #lt_scarr.
ENDMETHOD.
METHOD process_table. " <=== new method
LOOP AT table REFERENCE INTO DATA(line).
DATA(carrid) = line->carrid.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Use TYPE ANY or generic table type for parameters, TABLE parameters are obsolete:
FORM fill_table USING tab TYPE any
CHANGING ptab TYPE INDEX TABLE.
APPEND LINES OF tab TO ptab.
ENDFORM.
And yes, subroutines are obsolete themselves, use them only if you absolutely must do this, e.g. in legacy environment.
You don't need to indicate structure type for perform variable table. But you can get error on runtime if any field name change which are used in perform. Two working example below.
SELECT * FROM kna1 INTO TABLE #DATA(lt_kna1).
PERFORM test TABLES lt_kna1.
FORM test TABLES pt_kna1 STRUCTURE kna1.
*
ENDFORM.
Risky one:
FORM test TABLES pt_kna1.
*
ENDFORM.

Convert dynamic REF TO DATA structure to static

I created structure with three components, one of which is type ref to data and a table type of this structure. The problem is, how do I add data to this table?
It always has three components, but only one of them is discovered during processing, I always know two of them. Thus I always use the entire table type ref to data and then determine the type of this structure and create the table on it.
The issue here is that by doing this, even though I know two of the components, the whole itab will be dynamic, so I must use it in methods exporting/importing a type ref to data, which is inconvenient.
The method below will always return a table type ref to data, which is completely dynamic (type ref to data), but the structure of the table will always be like this:
component 1 -> type pc261.
component 2 -> type pay99_international.
compoment 3 -> well this is always a mistery hehe
methods get_payroll
importing it_rgdir type hrpy_tt_rgdir
returning value(rt_value) type ref to data.
method get_payroll.
field-symbols: <lt_payroll> type standard table.
create data rt_value type standard table of (mv_py_struct_type).
assign rt_value->* to <lt_payroll>.
...
endmethod.
My intention was to have the returning value with another type, a known type, with which I can use the two known components more easily. The idea I had was to create a type with only the unknown field as ref to data, than have a table of it.
This way, I would be able to use it inside methods without having to work so "dynamicaly", which altough works perfectly, is kind of difficult to understand only by reading the code.
types begin of gty_s_generic_payroll.
types evp type pc261.
types inter type pay99_international.
types nat type ref to data.
types end of gty_s_generic_payroll.
types gty_t_generic_payroll type table of gty_s_generic_payroll.
The problem is, how to use an itab of type gty_t_generic_payroll as declared above?
I must somehow create the component 3, but I have no idea how to do it...
At the end, I have a generic field-symbol, that is type table, that has the two known components + the third one that was discovered during processing time.
So how can I pass the content of this field symbol to a table type gty_t_generic_payroll?
data lt_payroll type ref to data.
field-symbols <lt_payroll> type any table.
lt_payroll = mo_payroll->get_payroll( lt_rgdir ). "this will return type ref to data
assign lt_payroll->* to <lt_payroll>.
After executing this code <lt_payroll> has all the values, but it is a dynamic table where I cannot use components <lt_payroll>[1]-inter.
So how to pass to gty_t_generic_payroll-typed variable, so that I can access components without much dynamics?
Given your target structure and table like this:
TYPES:
BEGIN OF payroll_row_type,
known_first_component TYPE something_we_know,
known_second_component TYPE something_else_we_know,
discovered_component TYPE REF TO data,
END OF payroll_row_type.
TYPES payroll_table_type TYPE STANDARD TABLE OF payroll_row WITH EMPTY KEY.
If you now have another table, whose type at runtime is:
TYPES:
BEGIN OF discovered_row_type,
known_first_component TYPE something_we_know,
known_second_component TYPE something_else_we_know,
known_third_component TYPE some_data_type,
END OF discovered_row_type.
TYPES discovered_table_type TYPE STANDARD TABLE OF discovered_row WITH EMPTY KEY.
You can move one to the other with
DATA source TYPE discovered_table_type.
DATA target TYPE payroll_table_type.
DATA resolved_component TYPE REF TO DATA.
DATA(descriptor) =
cl_abap_elemdescr=>describe_by_data( source_row-known_third_component ).
LOOP AT source INTO DATA(source_row).
DATA(target_row) =
VALUE payroll_row_type(
known_first_component = source_row-known_first_component
known_second_component = source_row-known_second_component ).
CREATE DATA target_row-discovered_component TYPE descriptor.
ASSIGN source_row-known_third_component TO FIELD-SYMBOL(<source_component>).
ASSIGN target_row-discovered_component TO FIELD-SYMBOL(<target_component>).
<target_component> = <source_component>.
INSERT target_row INTO TABLE target.
ENDLOOP.
The question and answers may look confusing for future visitors (what is the actual question?), so here is my two cents.
Summary of the question :
You call an external code (1) which gives you an internal table generated dynamically, but you know that all the components are always the same except one which varies but is at the same position, so you'd like to refer to its components statically, except for the one which varies.
(1) so, you can't adapt it.
Your workaround is to define an equivalent internal table statically and the component which varies will be defined as a data reference type (pointer to any data object), then to initialize it by copying the data from the dynamic internal table.
You ask for another better solution because yours consumes extra memory (two internal tables) and decreases the performance (copy process).
Answer :
No better solution
It looks like I was able to pass the values from the fully generic table (type ref to data) to another table that is 1/3 generic (type gty_t_generic_payroll):
methods get_payroll
importing it_rgdir type hrpy_tt_rgdir
returning value(rt_value) type gty_t_generic_payroll.
method get_payroll.
data lt_payroll type gty_t_generic_payroll.
data lt_payroll_aux type ref to data.
field-symbols: <lt_payroll_aux> type standard table.
create data lt_payroll_aux type standard table of (mv_py_struct_type).
assign lt_payroll_aux->* to <lt_payroll_aux> .
call function ' '.
call function ' '
exporting
= mv_relid
= mv_pernr
= xsdbool( gs_parm-use_natio <> abap_true )
tables
= it_rgdir
= <lt_payroll_aux> "table with the values I need
exceptions
= 0.
if sy-subrc <> 0.
return.
endif.
loop at <lt_payroll_aux> assigning field-symbol(<ls_payroll_aux>).
assign component 1 of structure <ls_payroll_aux> to field-symbol(<evp>).
assign component 2 of structure <ls_payroll_aux> to field-symbol(<inter>).
assign component 3 of structure <ls_payroll_aux> to field-symbol(<nat>).
data(ls_value) = value gty_s_generic_payroll(
evp = <evp>
inter = <inter>
).
get reference of <nat> into ls_value-nat.
append ls_value to rt_value. "returning table, with values I need and
"now with 2/3 known types
endloop.
endmethod.
At the end of the day, I acomplished what I needed, but unfortunately I do loose a lot of performance, since I must loop twice in the results now.
to populate the not-so-dynamic-table
to do the actual process of the report (at least it gets pretier lol)
This is the only way because I can't simply use insert lines of dynamic_itab to not_so_dynamic_itab, since the third component is reference .

Embed an type of other pkg into mine, and init it by literal

I read how to init embed type, and a related Q&A.
What my problem is when compile this code, I got :
[Error] unknown field 'feature.DefaultSshHelper' in struct literal of type dala02
type FDH feature.DefaultSshHelper
type dala02 struct {
Md5_v string
feature.DefaultSshHelper
//FDH
}
var x_01_h1_p = &dala02{
Md5_v: "",
feature.DefaultSshHelper: feature.DefaultSshHelper{
//FDH: FDH{
// blabla
},
}
// use it by a interface []feature.CmdFioHelper{x_00_h1_p}
At first time, I thought it was an Exported problem, so I added this line 'type FDH feature.DefaultSshHelper'. Now, we have this error :
[Error] cannot use x_01_h1_p (type *dala02) as type feature.CmdFioHelper in array or slice literal:
*dala02 does not implement feature.CmdFioHelper (missing Getnextchecker method)
But a pointer of feature.DefaultSshHelper does implement feature.CmdFioHelper ( a interface ). So pointer of dala02 should also implement that, right? (reference form effective go)
There's an important way in which embedding differs from subclassing. When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one.
Question is how to fix this compile error, which line is wrong? I'm not a expert for golang, thanks for your advice :). BTW I do find some workaround.
When you refer to embedded fields, you have to leave out the package name of the embedded type, as the unqualified type name acts as the field name.
Spec: Struct types:
A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct. An embedded type must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
So simply write:
var x_01_h1_p = &dala02{
Md5_v: "",
DefaultSshHelper: feature.DefaultSshHelper{
// blabla
},
}
Your other attempt type FDH feature.DefaultSshHelper falls short as this type declaration creates a new type with zero methods: the type FDH does not "inherit" the methods of feature.DefaultSshHelper. And thus any type that embeds FDH will also lack methods of feature.DefaultSshHelper.

ABAP: pass data type to form

I want to pass my own datatype to a form - but it doesn´t work:
TYPES: BEGIN OF my_type,
v1 TYPE i,
v2 TYPE i,
END OF my_type.
PERFORM calc using ...some parameters... .
FORM calc using ...some parameters... .
DATA values TYPE my_type " <- ERROR type my_type does not exist
...some code...
ENDFORM.
Remark: Based on more information in comments: The code is defined in a function module.
A function module is its own programm (the name is SAPL...function group name...). Each function module is its own include.
If you define a type in a report, a function module can't know the type definition. If you need to share a type definition between a reports and function modules (groups), you should define it as a global type in SE11.
If you run your code only inside a function module, you may define types in the top include of the function group. But you should not use this definition in the function module interfaces.

DB2 SQL array in attribute-defs of user defined type

I have a question concerning user defined types in DB2(v. 9.7.0.441). I want to create a type which has an attribute-array of another user defined type. Let me show you what I mean by a brief (fictional) example:
This is the UDT I want to use in another type
CREATE TYPE sport AS
(
Sport VARCHAR(10)
) MODE DB2SQL;
This is the UDT which should use the one above
CREATE TYPE person AS
(
plays sport ARRAY[3] // 'REF(sport)' or 'plays VARCHAR(10) ARRAY[3]' don't work either
) MODE DB2SQL;
DB2 just says that the token ARRAY[3] is unexpected.
Any hint what could be wrong here? By now it would be enough to have an CHAR Array in a UDT...
Thanks in advance
Ok ok,
according to db2's CREATE TYPE (array) statement "an array type can only be used as the data type of:
A local variable in a compound SQL (compiled) statement
A parameter of an SQL routine
A parameter of a Java procedure (ordinary arrays only)
The returns type of an SQL function
A global variable
and
A variable or parameter defined with an array type can only be used in compound SQL (compiled) statements
"
So its just not possible to use an array type inside a user defined type :-/
I would assume something like the following...
CREATE TYPE sport AS(Sport VARCHAR(10)) MODE DB2SQL;
CREATE TYPE PersonT AS(plays SportT ARRAY[3]) MODE DB2SQL;
CREATE TYPE SportArrayT AS SportT ARRAY[3];
CREATE TYPE PersonT AS (plays SportT SportArrayT) MODE DB2SQL;
However, the 3rd statement fails. Obviously an array of a user-defined type (or REF(SportT)) is not allowed :-(
Have a look at the doc for CREATE TYPE (array).
I'm not really sure what you're trying to do but the examples they give are like this:
CREATE TYPE CAPITALSARRAY AS VARCHAR(30) ARRAY[VARCHAR(20)]