Currently Being Moderated

In this weblog (weblog 12 of New Blog Series: ABAP Trial Version for Newbies) you get to know one of the most important tools for an ABAP developer, the debugger, and an important source of information that every developer needs: the ABAP keyword documentation. I will give you a short overview on the ABAP debugger and use it to find a particular bug. You will probably be pleased to learn that in the SAP AS ABAP it is very easy to start the debugger. You can diverge into the debugger from the normal state of the system. There is no need to start the system in a particular debugging mode in ABAP.

Moreover I will show you how to benefit from some really useful features of the ABAP keyword documentation. All these explanations are embedded in a practical example: We will change the program from ABAP Trial Version for Newbies Part 11: Getting More Familiar With the ABAP Dictionary in order to present fewer columns in the UI, to order the entries and to minimize the result set. In the course of doing this, you will learn:

  • How to define a structure
  • How to narrow the result set of a SELECT by reading less fields from the database
  • A particular addition the SELECT statement that enables you to restrict the number of fields transported into the target field of the SELECT.

Defining a Custom Structure in a Program

As a preliminary we copy the program from weblog 11 to the program y_select_f_flight_ad_2 . If you have any trouble doing this refer to weblog 11 where I describe how to copy a program y_select_f_flight_ad_1 . Let us start by defining a narrower structure than the one we had in our program. You remember that by defining wa_flight TYPE sflight we got a structure that was as broad as the table sflight with all of its fields. We assume, we need only some of its fields, namely: carrid , connid, fldate, price, currency, and planetype. So we add a new data definition:

DATA: itab_flight TYPE STANDARD TABLE OF sflight,
      wa_flight TYPE sflight,
      alv TYPE REF TO cl_salv_table,
      BEGIN OF str_flight_s,
        carrid TYPE sflight-carrid,
        connid TYPE sflight-connid,
        fldate TYPE sflight-fldate,
        price TYPE sflight-price,
        currency TYPE sflight-currency,
        planetype TYPE sflight-planetype,
      END OF str_flight_s.      

If you have read the weblog in which I introduced the Data Element, you know what additional benefit we get by using those Dictionary data types: They all have defined field texts. Since I intend to use the object-oriented way to output an internal table (look at ABAP Trial Version for Newbies Part 10: A First Little Business Program) we will profit from these texts by getting headers for all the table columns we output.

You may think that by now we do not even have an internal table that has the same line type of our new structure. And you are right. So let us create one:

itab_flight_s LIKE STANDARD TABLE OF str_flight_s. does the job for us. We use the keyword LIKE because we do not give a type for the table line, but a structure. Next we adapt the select statement:

SELECT *
  FROM sflight INTO TABLE itab_flight_s
  WHERE carrid = p_carrid AND seatsmax < 250.

Again we have an array fetch, because we select the whole result at once, and we have &#133; yes, we have a syntax error. Press CRT + F2, this is the keyboard short cut for the syntax check to see this.

A Useful Addition to the SELECT Statement

At second thought it is easy to understand what is wrong with our SELECT. By using the asterisk we read all columns of table sflight , and this does not completely match with structure str_flights_s . Of course, there is a partial match, because the structure str_flights_s contains only fields that are typed with the respective types of the columns of sflight, but it does not contain all the fields of this database table, only a subset. Wouldn't it be nice if we could tell the program: Move just the fields from the result set to the target structure that have a counterpart in this structure. And indeed, there are some keywords in ABAP that do this job. We adapt the SELECT statement again:

SELECT *
  FROM sflight INTO CORRESPONDING FIELDS OF TABLE itab_flight_s
  WHERE carrid = p_carrid AND seatsmax < 250.

But be careful with the keywords INTO CORRESPONDING FIELDS. They can do no magic, but use the identity of the names for the assignment: That is the value of the selected entries from database table column A are moved to the fields in column A of the internal table. And this is all. In our case, the fields with an identical name also are of the same type, but if this would not be case this is not checked by the system.

Next we use the object-oriented way to output our internal table. In order to get some additional information in case the internal table itab_flight_s is empty we add a condition. So our code looks like this:

IF itab_flight_s IS INITIAL.
  WRITE: 'nothing in table.'.
ELSE.
  cl_salv_table=>factory( IMPORTING r_salv_table = alv
                        CHANGING  t_table      = itab_flight ).
  alv->display( ).
ENDIF.

We outcomment the two alternative ways to output the table (mark the relevant code and press CRT + SHIFT + "<"), save, activate the program, and run it.

What Is Wrong With Our Program &#150; We Start to Debug

We know from weblog 11 that there is a result set with some entries in it if we choose Lufthansa in the selection screen as the value of the parameter p_carrid and so we provide the same value for this parameter. Unfortunately the result is not satisfying:

image

It might seem hard to understand why we do neither get the output "nothing in table" nor an output showing some table entries. So this is the time to resort to the debugger. To see what our SELECT statement does at runtime we set a breakpoint at this line. We do this by double clicking the leftmost column in the editor as shown and a small icon appears that stands for a breakpoint:

image

Before starting to debug we check if we have really chosen the new debugger. In fact your system should already be configured accordingly. If not we open the menu: Utilities &#150; Settings &#150; ABAP Editor &#150; DEBUGGER and select "New Debugger". And now let us go. We run the program, choose the input parameter Lufthansa and select Execute or press F8:

A new external mode opens and we see the new debugger. Let me use this opportunity to give you some general information on the debugger before we go into the details of how to find our bug.

The New ABAP Debugger &#150; A Short Overview

You know, you live in good times, at least as far as the ABAP debugger is concerned. Since NetWeaver 2004 there is a completely new debugger that runs in another work process than the program that is debugged, the debuggee. This is why the new debugger always starts in a new external mode.

To put it in a nutshell: This debugger is a state-of-the-art tool that offers the features you expect from any debugger, even some features more (for example a tool to compare the contents of any two internal tables). The navigation within the debugger is straight forward, and you can easily configure the different tools in it as you like. As for the general layout of the debugger, it is divided in different tabs. Each tab stands for a desktop of its own, that can contain different tools, which, for example, show the source code, the call stack, or the value of variables etc. You can customize each desktop by inserting the tools you like in the position you want. To give you a general impression of what such a desktop in the debugger looks like let me show you a screenshot of the standard desktop with its three tools:

image

Below the menus that are not shown in this screenshot (experienced bloggers

on SDN know: the size of pictures in SDN blogs is limited ) there is are some buttons to control how to step through the debugged code (5). In the panes below you see the standard desktop (1) with the source code tool (2), the call stack (3) and the variables and their values(4). So much for the overview of the debugger. But to really show you how to work with it we go on searching our bug.

Debugging Our Program

As the debugger has opened with desktop 1 we first choose the standard desktop tab to see the tools as shown in the figure above. We double click the name of the internal table itab_flight_s in the code view. That has the effect that the debugger shows the value of this variable in the pane on the right (4 in the figure above):

 

image

If you were more experienced with the ABAP debugger, this display would already tell you that we have an internal table with six columns and no line. So you can just guess it or must believe me. To make sure that this is the right way to understand what we see we double click the name of the internal table in this pane: We get to the tab rider that shows the content of the internal table so that we can check, if there were any lines to be displayed:

 

image

There are none. We navigate back to the standard desktop by using the Back button. Next we want to execute the SELECT statement and then look again at the content of the internal table. So we need a single step, and quite obviously the icons to control the debugging steps look as in most other debuggers, and anybody familiar with debugging will have no problems to choose the right debugging steps in the ABAP debugger:

 

image

We select the single step mode as shown, look again at the content of the internal table in the right pane below. Obviously our internal table is now populated with 33 entries.

image

So we can feel relieved: There was no mystic loss of data in the system since the weblog 11 when we had quite a number of entries for the carrid of Lufthansa. We go on in the single step mode, and see that the first branch of the if-statement is not taken. This is because the internal table is not empty. While we are stepping forward we have an eye on the content of the internal table in the pane on the right. It does not change until we reach the display method. So how could it be that there are no lines output, if the value of the internal table it not empty and this table is output?

Obviously we have so far explicitly verified only the first part of the condition. So do we really output the internal table, which has 33 lines as the debugger tells us. We have a closer look at the relevant statement:

cl_salv_table=>factory( IMPORTING r_salv_table = alv
                        CHANGING  t_table      = itab_flight ).
alv->display( ).

And there is the culprit. We have passed the wrong table to the factory method. We double click itab_flight to view it in the variables tool. The table is empty, and this takes little wonder. It is the table we used in the weblog 11. Since we have not deleted its definition it does still exist in the program, but no line was added to it. Remember: We meant to replace its name by the name of the table itab_flight_s in all statements. But it seems, we have forgotten one statement, namely the one in which an internal table is passed to the factory method. So the table itab_flight is still empty, and it is this empty table that we pass to the factory method. This is also the explanation of why our output showed many more headers for columns than our new narrow table s_flight_s . We showed the old table s_flight with all columns of the database table sflight and no content, because the result of the SELECT statement was moved to the new internal table s_flight_s .

So we correct the statement accordingly, activate, save the program, and by double-clicking our breakpoint we remove it: For the time being we do not need the debugger, we are fully confident that we have corrected the mistake, and we are right.

Let me use the last sections of this weblog to tell you a bit about good SQL programming style and something more about the ABAP language documentation as I have announced at the beginning of this weblog.

Some Words on Efficient SQL Programming

First of all, you probably know already that it is bad programming style to select more data from the database that is needed or used. Why is this so? In general, in a real-life system accessing the database is expensive. You have the network latency and you have to access the hard disk if the table is not cached. In general, both activities are far more time consuming than the execution of simple statements on the application server that do only affect the memory of the work area of the process the program runs in. Selecting all fields from a dataset on the database if in fact you move only a few fields to the target structure is as efficient as carrying ten buckets of water to the tenth floor and then pour five of them away. Of course, it does not really matter in our little example, but if you have result sets with some hundred thousands of datasets, you are well-advised to select only the fields you really use:

So we adapt our select statement to:

SELECT  carrid fldate planetype currency price connid
  FROM sflight INTO CORRESPONDING FIELDS OF TABLE itab_flight_s
  WHERE carrid = p_carrid AND seatsmax < 250.

I have chosen a sort of random order for the columns just to show you that this order does not matter because the fields of the result set are moved according to their name. The order is irrelevant.

How to Use the ABAP Language Documentation Efficiently

Being economical we want to order the flights in the result by the price and the date. Most probably we need an addition to the SELECT statement. If you are not sure what the relevant addition you need looks like in detail, just position the cursor on the keyword SELECT and double click. A dialog window opens:

image

We double click the first alternative and get to a window with a tree in the pane on the left:

image

It shows the nodes and leaves under the node SELECT. Each node and leave corresponds to a page that is shown in the pane on the right. You can navigate to the respective page by double clicking a node or leave in the tree. The navigation within in the tree is quite as you expect it. We see that the SELECT node is marked and the corresponding page is shown. The entry for the SELECT node starts with an overview of the syntax of this statement:

 

image

We click sort key and get to the page that informs us in more detail:

 

image

So this should suffice to give you an impression of how you can drill down on the topic you need in the ABAP language documentation.

You can use the arrow heads on top of the page to navigate back and forth to pages you have already opened. The button bar offers some other useful functions you might need:

 

image

I guess the tool tips require no further explanation.

So much for the explanation of the ABAP keyword documentation. To learn more about the ABAP keyword documentation have a look at a ABAP Geek 9 - ABAP Keyword Documentation for SAP NetWeaver Application Server in which this source of information is introduced by its author.

Let us now go on with our example and enhance our SELECT statement by the keywords we have just found:

SELECT *
  FROM sflight INTO CORRESPONDING FIELDS OF TABLE itab_flight_s
  WHERE carrid = p_carrid AND seatsmax < 250
ORDER BY price fldate.

We save, activate and run the program. Fortunately, this time it behaves as we have expected.

Summary

By now you should be able to use the debugger and to find your way in the ABAP keyword documentation. In a sense, you can now stand on your own feet in ABAP: You know how and where to find information on the details of the ABAP semantic and syntax. And you are able to track down the source of misbehavior if your program seems to lead a live of its own and does not what it is expected to.

So in the next weblogs I will explain not every new keyword we use as extensively as I used to. But as there is far more to developing in a language than knowing the details of its keywords there still remains a lot of work to be done in this series. In particular we will show you in the next weblogs how to create database tables in the ABAP Dictionary and relate them by a foreign key relationship. We will fill these tables with entries from a text file we put in a directory of the server. And this is only the beginning. Some weblogs later we will encapsulate our program logic so that we can call it from a state-of-the-art UI: an ABAP Web Dynpro View. At this stage you will learn the basics of Web Dynpro ABAP and how it interacts with the backend logic. So we hope this short sketch of what else is going to come will heighten you interest in this series.

Comments

Actions

Filter Blog

By date:
By tag: