Friday 6 November 2009

Internal Inspector

Recently, Jorge Rojas, (A big welcome ;) ) told me about a way to search through the internal components of an ABAP program. It takes a bit of searching, but once found, it is a very interesting too.

What happens when you want to know which DB tables are being used on a program? Or which Function Modules are being called?

I needed to do this because I wanted to make sure that the order in which to apply the transport of different objects to a QA system.

It is a very simple 3-step process:

1. You have to know the name of the program and put it in the Tx. SE38, but do not open it!


2. Right-click the field and select the Internal Program Environment Option (F9)


3. Select the options you want to search in the program.



Extra step. Enjoy!

Friday 13 February 2009

Editing a table

Just a quick post for a couple of nice features I learnt today:

First. To edit 'ala-brute-force' a table, the transaction SE16N can provide a nice little trick:
It shows the contents of the table in a beautiful ALV Grid, but to edit them, send the system a new ucomm with code SAP_EDIT, so if you send the code '&sap_edit' in the command line, the table becomes editable.... that's a new trick!

Second, I had some trouble reading an information from a dynpro in a running program. I tried the DYNP_VALUES_READ function module, but it didn't work, so I learnt the following trick:

[code]
data: variable_name type string value '(program)field', value type data_type.
field-symbols type data_type.
assign (variable_name) to .

value =
[/code]

The good part here is the '(program)field' concept. I didn't know you can access a field of another program using that syntax. A bit.... dark this concept, but can save your life sometimes ;)

Wednesday 7 January 2009

When there is no other way, or how to use the BSEG table

Well, well....

I am writing this post while one of the programs I am coding, the one related to the BSEG table executes.

And the post is related with this program, because I said before that the BSEG table should be avoided, but there are times, like this when there is no other option.... OR the other option (if there is one) is too complicated to implement and.... you are just too lazy to do it on time because you have no time left to waste there.

Anyway, the thing is, reading the Performance and Tuning forum on SDN I found that there is a general consensus that using the for all entries (i.e. selecting info from the DB, based on already existing info of an internal table) is bad bad bad!. I didn't know that, and I used the for all entries for almost everything... but now, running a simple select of a big table, with a for all entries... it is the same as enjoying the summer in hell.

This is the dreadful select:


select bukrs
belnr
gjahr
buzei
[...]
into corresponding fields of table it_bseg
from bseg
up to n rows
for all entries in git_bkpf
where bukrs = git_bkpg-bukrs and
belnr = git_bkpf-belnr and
gjahr = git_bkpf-gjahr and
buzei in rg_dummy_buzei.


That had awful results. The idea was that with the up to n rows line, the thing would improve a lot (n was 1000 at first, so it was a very small quantity of rows to select)... but to be honest, the thing broke just like the others, if not worse.

I then realized the central idea of this post: if you need to use the BSEG table, then do not use joins (because you can't! hahaha) and never use for all entries, because they are one of the roots of evil. Use a very minimalistic select and try to give the whole key to the compiler, even if it has empty ranges on it:


select bukrs
belnr
gjahr
buzei
[...]
into corresponding fields of table it_bseg
from bseg
up to n rows
where bukrs in s_bukrs and
belnr > cursor_belnr and
gjahr in rg_dummy_gjahr and
buzei in rg_dummy_buzei.



Sorry for the quality of the code text... I will try to use CSS for this... when I learn how to use CSS ;)

Monday 5 January 2009

BSEG Table: Just avoid it

The BSEG Table, the "Accounting document segment" is a cluster table that, as far as I understand, stores all the information for almost every financial movement on the SAP system. As you can maybe guess, this can be (and IS) a huge table, and there is a lot of information there that, to be read takes HUGE amount of time. Because of this, programmers (and users) do not like to read (or use programs that read from) the BSEG table directly. As a cluster table, this is not a real DB table, but a somehow "logical" table and you can use the real DB tables that make this big monster, instead.

The structure for this is:

BKPF: Is the Accounting document header, therefore, the hub that links all the others...

And all the others are:
I (Open Items):
BSIK [K (Vendors)]
BSID [D (Customers)]
BSIS [S (G/L Accounts)]

A (Cleared Items)
BSAK [K (Vendors)]
BSAD [D (Customers)]
BSAS [S (G/L Accounts)]

This shows how all table relate to each other and how the name scheme works. It becomes much clearer now!

Another tip I just read: The key for the BSEG table is built from the BUKRS, BELNR, GJAHR and BUZEI fields. If you can get the first three fields, the fourth can be used in the select even if you don't have it. Just create an empty RANGES for that field and in the WHERE clause, use something like 'BUZEI IN EMPTY_RANGE' to give the whole key to the compiler.

Saturday 3 January 2009

Check and Review

Checking and reviewing should now be my best new friends.

I had an assignment for 3 days and the last two of them were used to find and fix an stupid problem that ended in dumps all the time. The program was really simple: create a backup of the table T059Z with the added field TEXT from its text table T059ZT, in a Z-table with the corresponding fields. The code is simple, by definition:

Create an internal table with the Z-table structure.
Select from T059Z with inner join to T059ZT the fields to backup.
Delete the old DB info.
Insert the new DB info.

The problem was when inserting the new info: a runtime error occurred at the very first record to insert:

ABAP runtime errors DBIF_RSQL_SQL_ERROR
Occurred on 03.01.2009 at 10:36:21

SQL error 1438 occurred when accessing table "ZTFI026 ".

What happened?

When writing a data record to the database (i.e. when
updating the database), only part of the data field was
written (updated). The rest was truncated.

What can you do?

If the error occurred in Open SQL, there is probably an inconsistency
between the NAMETAB and the ABAP/4 Dictionary.
Compare the length specifications of the fields in the NAMETAB with
those in the ABAP/4 Dictionary and contact someone who is able to
perform a consistency check and eliminate the problem.
In most cases, this person will be your SAP consultant.
Please make a note of the actions and input which caused the error.

*


(...)

Error Analysis

The problem has arisen because, within the database interface,
one of the data buffers made available for the INSERT (UPDATE)
is longer than the maximum defined in the database.
On the other hand, it may be that the length in the NAMETAB
does not match the maximum length defined in the database.
(In this case, the length in the NAMETAB is longer.)


I do not know why but my workmate, who was in charge of creating this table in particular, never checked or reviewed his work, then giving me 2 days of more work looking for the solution, which was really simple and it became pretty clear by reading OSS note 591600. The table definition was wrong: one of the fields had the wrong data element:


MANDT MANDT CLNT 3
LAND1 LAND1 CHAR 3
WITHT WITHT CHAR 2
WT_WITHCD WT_WITHCD CHAR 2
QPROZ QPROZ DEC 5
QSATZ QSATZ DEC 4
TEXT40 TEXT40 CHAR 40


compared to:


MANDT MANDT CLNT 3
LAND1 LAND1 CHAR 3
WITHT WITHT CHAR 2
WT_WITHCD WT_WITHCD CHAR 2
QPROZ QPROZ DEC 5
QSATZ WT_QSATZ DEC 7
TEXT40 TEXT40 CHAR 40


This is a reminder of why do I check and review my work once or twice... sometimes even more.