Retrieving Object names and Transfer requests for an entire package programmatically - abap

I have two separate system (development and testing) and I need to check that for all my objects (programs and all includes) the version in development matches that in dev. I can do this manually by going to SE80 -> Utilities -> Version Management for each object but for hundreds/thousands of objects this is extremely time consuming.
Is there a way to retrieve the object name and TR programatically so that they could be output to a table or spreadsheet?
EDIT. (Vwgert it seems to me like this works - if it doesn't could you explain a bit more why it won't? Thanks)
So using the following JOIN I believe I am able to retrieve all the objects, types and latest TR in the system.
SELECT a~obj_name b~korrnum c~object b~datum b~zeit
FROM tadir AS a
INNER JOIN vrsd AS b
ON a~obj_name = b~objname
INNER JOIN e071 AS c
ON a~obj_name = c~obj_name
AND a~pgmid = c~pgmid
AND a~object = c~object
INTO TABLE gt_obj_tr
WHERE a~devclass IN s_pkg.
SORT gt_obj_tr BY object ASCENDING obj_name ASCENDING korrnum DESCENDING datum DESCENDING zeit DESCENDING.
DELETE ADJACENT DUPLICATES FROM gt_obj_tr COMPARING object obj_name.

You can find most of the object headers in the table TADIR. The request and task headers are stored in E070, the entries in E071 - just take a look at the contents, it's fairly self-explanatory if you know what a transport looks like. Be aware that some object types can be transported partially (R3TR CLAS is the entire class, LIMU METH is only a single method) - this makes direct joins impossible.

Probably the easiest (although not pretty) is to use table REPOSRC and link that to VSRD. REPOSRC is the table containing all the source code (methods, programs, functions) in the system so you can be sure you don't miss anything. You'll probably do something like (rough pseudo code):
SELECT name FROM reposrc
WHERE name LIKE 'Z%'
OR name LIKE 'SAPLZ%'
OR name LIKE 'SAPMZ%'
SELECT objtype objname FROM vrsd
WHERE objname = reposrc-name
AND objtype IN ('CINC', 'REPS') "Class include & reports
This of course is just source code but it sounds like thats all you need. If you need to get from the report name to the real abap object (method, class, function module) use function module SEO_CLASS_GET_NAME_BY_INCLUDE and for functions look it up on table TFDIR.

Related

How can you select JSON object key values using SQL

I have some records in my database in a column called Swatch, that are JSON to describe a colour swatch. Each record looks something like this:
{"colors":{"color-1":"transparent","color-2":"transparent"}}
Basically it's one big colour object with lots of key value pairs. I would like to manipulate this JSON, using SQL, to achieve something like this instead to allow customisable colour names.
{"colors":[{"name": "Red", "color":"#00000"},{"name": "Green", "color":"#00000"}]
(Hex codes are just for demo purposes, I know they're not legit).
How can I achieve this? It is possible using SQL Server?
It may be possible, but a lot depends on the data and what you are trying to achieve.
There is a set of JSON functions available, most of them added in SQL 2016, and a pair more should be available in SQL Server 2022.
If you want to erase the current structure and data in favor of a new one that's easy.
If you want to convert your current structure to a different one, that might be pretty hard, but it's highly data related.
Let's consider your samples as the actual data you want to convert
{"colors":{"color-1":"transparent","color-2":"transparent"}}
{"colors":[{"name": "Red", "color":"#00000"},{"name": "Green", "color":"#00000"}]}
Here are the issues and complications I see
how can you say what color-1 is? what name does it have? that's human operation unless you have some ColorCode-ColorName table
Do you have a fixed/known amount of color-N keys? to get the property value cleanly you will need to reference them explicitly. (but I'm sure you can find other ways... without using JSON functions tho)
to change the structure you need to extract the data and build the new JSON string, basically a lot of string concatenation that will require quite some time to build and test
JSON function samples
I've played around with the JSON data and created some sample queries, I hope trying them will help you understand what it means to manipulate JSON data, and choose if SQL Server is a fitting tool for your task
-- key-values property
DECLARE #jdata2 as varchar(200) = '{"colors":{"color-1":"transparent","color-2":"transparent"}}'
SELECT
JSON_VALUE(#jdata2,'$."colors"."color-1"') AS Color1
,JSON_VALUE(#jdata2,'$."colors"."color-2"') AS Color2
,JSON_VALUE(#jdata2,'$."colors"."color-3"') AS Color3
GO
-- objects and arrays
DECLARE #jdata as varchar(200) = '{"company":"Contoso","colors":[{"name": "Red", "color":"#00000"},{"name": "Green", "color":"#00000"}]}'
SELECT JSON_QUERY(#jdata,'$.colors[0]')
SELECT JSON_VALUE(#jdata,'$.colors[0].name')
SELECT JSON_VALUE(#jdata,'$.company')
--Update property
SELECT JSON_MODIFY(#jdata,'$.company', 'Northwind')
--Add property
SELECT JSON_MODIFY(#jdata,'$.country', 'Italy')
--Add new Object
SELECT JSON_MODIFY(#jdata,'$.salesman', JSON_QUERY('{"name":"Mario","surname":"Rossi"}'))
--Append new Object in an Object array
SELECT JSON_MODIFY(#jdata,'append $.colors', JSON_QUERY('{"name":"Yellow", "color":"#00000"}','$'))
------ About DELETING
--Delete (whole) Property works fine
SELECT JSON_MODIFY(#jdata,'$.colors', NULL)
-- deleting sometihng inside an array is not fine at all
-- Should delete 1 value/object from the array... but no, 'null,' is left instead
SELECT JSON_MODIFY(#jdata,'$.colors[1]', NULL)
-- To "delete" properly pass the whole array or object array omitting the deleted value...
SELECT JSON_MODIFY(#jdata,'$.colors', JSON_QUERY('[{"name": "Green", "color":"#00000"}]'))

AS400 RPGLE/free dynamic variables in operations

I'm fairly certain after years of searching that this is not possible, but I'll ask anyway.
The question is whether it's possible to use a dynamic variable in an operation when you don't know the field name. For example, I have a data structure that contains a few hundred fields. The operator selects one of those fields and the program needs to know what data resides in the field from the data structure passed. So we'll say that there are 100 fields, and field50 is what the operator chose to operate on. The program would be passed in the field name (i.e. field50) in the FLDNAM variable. The program would read something like this the normal way:
/free
if field50 = 'XXX'
// do something
endif;
/end-free
The problem is that I would have to code this 100 times for every operation. For example:
/free
if fldnam = 'field1';
// do something
elseif fldnam = 'field2';
// do something
..
elseif fldnam = 'field50';
// do something
endif;
Is there any possible way of performing an operation on a field not yet known? (i.e. IF FLDNAM(pointer data) = 'XXX' then do something)
If the data structure is externally-described and you know what file it comes from, you could use the QUSLFLD API to find out the offset, length, and type of the field in the data structure, and then use substring to get the data and then use other calculations to get the value, depending on the data type.
Simple answer, no.
RPG's simply not designed for that. Few languages are.
You may want to look at scripting languages. Perl for instance, can evaluate on the fly. REXX, which comes installed on the IBM i, has an INTERPRET keyword.
REXX Reference manual

Rails query the last of each type

I am using STI and have a table Widget that a bunch of other subclasses inherit from using STI. I want a query that gets the last created of each object with a uniq type.
I have a predefined array of types I want so lets say:
types = ["type1", "type2", "type3"]
So my query would be something like: (this doesnt work)
Widget.where(type: types).uniq.reverse
My goal is to get the last of each object that matches 1 of those types..
Not 100% sure, but something like this might work (untested):
ids = Thing.where(type: types).group(:type).maximum(:id).values
last_per_type = Thing.find(ids)
Thing.select("distinct type")
By the way, type is a special variable in rails and can't be used as a column name.

Two queries related in UniObjects for .NET

Context
I have a interface in VB.NET that extract the data from the UniVerse using UniObjects for .NET
Problem
From the COB file I need to get all keys where the FEC.COB field is equal to a specific date and the field SEC is equal to 04.
An expert in UniVerse Database told me that I can run the follow queries:
SELECT COB WITH FEC.COB > “31/10/2013”
SELECT.ID 1 2 04
But I don't know how can I do that with UniObjects library. Can anyone help me?
I don't use UniObjects as my shop normally gets data our of UniVerse via ODBC. Also my VB is bad, so I don't have much metacode for you, but the basic idea would be to do something like this.
1.) Create a UV Session. Hopefully you have that much worked out as I can be of next to no help there.
2.) Once the session is established Execute your query by doing something like this
session.Command.Text = "SELECT COB WITH FEC.COB > '31/10/2013'"
session.Command.Exec
(I converted your double quotes to single quotes and Universe won't mind).
3.) If you just need the IDs, you can get them by iterating through the select list that your query returns. A command line query will always return to list 0 unless you specify otherwise in your UV query. In most cases your results will be in session.SelectList(0)
Dim objSelect As object
Set objSelect = objSession.SelectList(0)
4.) It looks like the SelectList object has a ReadList method which returns a Dynamic Array Object, which you should be able to iterate through using normal array looping. Additionally you can use a while loop and next to do what you need to do.
Dim someObject as Object
someObject = objSelect.Next ' Get first ID
Do While Not objSelect.LastRecordRead
' Do something here with someObject. Maybe ToString it or something
someObject = objSelect.Next' Get next ID
Loop
Hope that is somewhat helpful.

QTP, access to QC field by label

I want to update a custom user field in QC using the Label of field instead of the name
At the moment we are doing it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("RN_USER_03") = 1
currentRun.Post
But I would like to do it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("Data Rows Passed") = 4
currentRun.Post
But I can't find the method to do it with.
Any Ideas?
Implying all labels are unique (which I doubt..):
You could create a function which accepts a label, searches in QC's tables that define customized fields for the correct field definition, and returns the field name. Then use the function's result value as the indexed property's index.
Suppose that function would be called "GetNameOfLabel", then the Caller's code would look like:
Set currentRun = QCUtil.CurrentRun
currentRun.Field(GetNameOfLabel ("Data Rows Passed")) = 1
currentRun.Post
Of course, the function would not really be trivial, but easy enough after some digging in the QC data model and finding an efficient way to fetch the name from the DB via SQL.
Or, the function could look up the name in an array, or a dictionary, then you would have to maintain that dictionary, but you would not have to go to the database for each lookup.
Disadventages:
Scripts with the wrong label might be harder to be debug
If labels are not unique, it might be real "fun" to debug
If looking up on the DB:
All scripts slow down if you don't cache, or pre-load, SQL query results for those lookups;
complexity, as you have to do the right SQL query, and you depend on QC's data model in a quite peculiar way (usually a horror when you're upgrading)
If looking up in an array, or dictionary:
You either must maintain its initialization (bet other admin guys adding a cust field will forget that easily), or must "load" it from QC's table (which is a bit like the SQL solution above, and has the same downsides).
I'd go with the array/dictionary-initialized-from-db-idea. Or, if you can live with the constant idea already presented, that one is a good bet. Considering that there is no session-independent scope in QCs customizing scripts, the SQL access idea might really kill performance because it would have to be executed for every new user session. Which is why I, too, +1'd the constant idea.
Look at this:
Dim gFieldLabelToNameDICT: Set gFieldLabelToNameDICT = CreateObject("Scripting.Dictionary")
gFieldLabelToNameDICT.CompareMode = vbTextCompare
Function GetNameOfLabel (strFieldLabel)
' If it doesn't exist yet in fieldLabelToName dict -> search it using TDC and add it to the list to improve performance
If Not gFieldLabelToNameDICT.Exists(strFieldLabel) Then
Dim testSetFields As List
Dim testSetFields: Set testSetFields = QCUtil.QCConnection.Customization.Fields.Fields("RUN")
For Each aField in testSetFields
If aField.UserLabel = strFieldLabel Then
gFieldLabelToNameDICT.Item(strFieldLabel) = aField.ColumnName
End If
Next aField
End If
GetNameOfLabel = gFieldLabelToNameDICT.Item(strFieldLabel)
End Function
Maybe you shall want to add some more error handling, such us considering the case that the label is not found.