donderdag 10 februari 2011

Copy transports between 2 SAP-systems

This explaination is written for when you want to copy transports between 2 SAP-systems.
During the explaination the example of transport DH1K906527 is taken.

Step 1: Find the transports

Search the directory of the transports via transaction AL11.
Normally these transports are in a directory with the name DIR_TRANS or /usr/sap/trans and contain out of 2 parts (cofiles and data-files)

For example:
      usr/sap/trans/cofiles/K096527.DH1
      usr/sap/trans/data/R096527.DH1

Step 2: Download the transports

Go to transaction CG3Y
  1. Fill in the filepath on the sap-server for the transport that you want to download (both cofile and data-file)
            usr/sap/trans/cofiles/K096527.DH1
  1. Fill in the filepath where you want that the file is stored

Step 3: Upload the transports

Go to transaction CG3Z
  1. Fill in the filepath where the file of the transport is stored
  2. Fill in the filepath on the sap-server where you want that the transports are stored
            //ontw-o001a/sapmnt/trans/cofiles/K096527.DH1
            //ontw-o001a/sapmnt/trans/data/R096527.DH1

Step 4: Activate the transports

Go to transaction STMS
  1. Click on the lorry (Import Overview – F5)
  2. Double click on the queue of Development
  3. In the menu goto Extra\Other Requests\Add choose for transport DH1K906527
  4. The transport is added to the list
  5. Select the transport and click on the lorry (Import Request)

donderdag 16 december 2010

Delete payroll results

I had the problem on a DEV-environment that the PY-results were a mess. I had double keys in the PCL2 table that made it impossible to remove the data via the standard SAP-programs RPUDEL20 or RPCDPU01.

That is why I created my own program that is based on the Logical database PNP.

Please handle with care, you don't want to execute this program on you Productive-systems

REPORT  ZHR_DEL_PY.

TABLES: pernr.

DATA: BEGIN OF rgdir OCCURS 0.
        INCLUDE STRUCTURE pc261.
DATA: END OF rgdir.
DATA: C_PERNR(8), C_SEQNR(5).
DATA: SORTFIELD(40).

RANGES: SORTFD FOR SORTFIELD.

START-OF-SELECTION.

GET PERNR.

* READ THE RGDIR
  REFRESH RGDIR.


  CALL FUNCTION 'CU_READ_RGDIR'
    EXPORTING
      persnr             = pernr-pernr
      no_authority_check = 'X'
    TABLES
      in_rgdir           = rgdir
    EXCEPTIONS
      no_record_found    = 1
      OTHERS             = 2.

  LOOP AT rgdir.
    MOVE pernr-pernr TO C_PERNR.
    MOVE rgdir-SEQNR  TO C_SEQNR.

    CONCATENATE C_PERNR C_SEQNR INTO SORTFD-LOW.
    SORTFD-SIGN = 'I'.    "in
    SORTFD-OPTION = 'EQ'. "equal
    APPEND SORTFD.
  ENDLOOP.

  CHECK SY-SUBRC = 0.

  DELETE FROM PCL2
    WHERE RELID = 'RB'
    AND  SRTFD IN SORTFD.

  DELETE FROM PCL2
    WHERE RELID = '$$'
    AND  SRTFD IN SORTFD.

  DELETE FROM PCL2
    WHERE RELID = 'CU'
      AND SRTFD = pernr-pernr.

  IF SY-SUBRC = 0.
    LOOP AT RGDIR.

      DELETE FROM HRPY_RGDIR WHERE
                           PERNR = pernr-pernr AND
                           SEQNR = rgdir-SEQNR.

      DELETE FROM HRPY_WPBP WHERE
                           PERNR = pernr-pernr AND
                           SEQNR = RGDIR-SEQNR.

      DELETE FROM HRPY_GROUPING WHERE
                           PERNR = pernr-pernr AND
                           SEQNR = RGDIR-SEQNR.

      DELETE FROM P01O_ZVB_RR WHERE
                           PERNR = pernr-pernr AND
                           EAPER = RGDIR-FPPER.

    ENDLOOP.
  ENDIF.

  COMMIT WORK.

  WRITE: / 'You deleted <', pernr-pernr, '>'.

END-OF-SELECTION.

Example subroutine programming: Delete content of a table

Below you can find an example of dynamically creating source-code.
For my example, I created a program that allows you to fill in a tablename and that removes all the content of the table that you've filled in.

Don't try this @ home, unless you know what you are doing.

REPORT  ZHR_DELETE_TABLE_CONTENT.

  DATA:  lt_code(100)     TYPE c OCCURS 0 WITH HEADER LINE,
         lv_repid         LIKE sy-repid,
         mess TYPE string,
         sid  TYPE string.

  PARAMETERS: p_table TYPE string OBLIGATORY.

  INITIALIZATION.

    IF sy-uname NE 'VERSTOCT'.
      MESSAGE 'PROGRAM NOT ALLOWED FOR THIS USER' TYPE 'E'.
    ENDIF.

    IF sy-sysid NE 'DEV'.
      MESSAGE 'PROGRAM NOT ALLOWED ON THIS SYSTEM' TYPE 'E'.
    ENDIF.

  START-OF-SELECTION.

    REFRESH lt_code.

    lt_code = 'PROGRAM TEMP.'.
    APPEND lt_code.

    lt_code = 'FORM DELETE_TAB.'.
    APPEND lt_code.

    CONCATENATE 'DELETE FROM' p_table '.' INTO lt_code SEPARATED BY space.
    APPEND lt_code.

    MOVE 'COMMIT WORK.' TO lt_code.
    APPEND lt_code.

    lt_code = 'ENDFORM.'.
    APPEND lt_code.

    GENERATE SUBROUTINE POOL lt_code NAME lv_repid
           MESSAGE mess
           SHORTDUMP-ID sid.

    PERFORM ('DELETE_TAB') IN PROGRAM (lv_repid).

    WRITE: / 'The content of table <', p_table, '> is gone.'.

GENERATE_SUBPOOL_DIR_FULL in cl_alv_table_create=>create_dynamic_table

Because the standard SAP method "Create_dynamic_table" can give the runtime error GENERATE_SUBPOOL_DIR_FULL, it should be avoided to use it.

  CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      i_structure_name = 'YSDXX_CLST_DATA'
    CHANGING
      ct_fieldcat = lta_fcat.

   CALL METHOD cl_alv_table_create=>create_dynamic_table
     EXPORTING
       it_fieldcatalog = lta_fcat
     IMPORTING
       ep_table        = dr_content. 

Instead use the code below,

lo_struct ?= cl_abap_typedescr=>describe_by_name( 'YSDXX_CLST_DATA' ).
lt_comp  = lo_struct->get_components( ).
APPEND LINES OF lt_comp TO lt_tot_comp.
l_struc = cl_abap_structdescr=>create( lt_tot_comp ).
l_struc_table = cl_abap_tabledescr=>create(
                        p_line_type  = l_struc
                        p_table_kind = cl_abap_tabledescr=>tablekind_std
                        p_unique     = abap_false ).

CREATE DATA lw_global_data-datatab TYPE HANDLE l_struc_table.

maandag 8 november 2010

shortdump GENERATE_SUBPOOL_DIR_FULL

There's a limit on the number of sub-routines that can be generated within a program. This limit is 36 and anythng over this will create a short-dump(GENERATE_SUBPOOL_DIR_FULL).

The reason why SAP has put this limitation on it is, is to avoid an overflow of the program memory. Changing this number is not possible because it is a kernel constant and therefore, not variable and removing memory segments from the PXA is currently not supported by the kernel...

So you need to look for another solution.
There are 2 main reasons why you would want to generate a subroutine:
1. To create a dynamic structure
2. To create a dynamic program

Let me give you the solution for those 2 types of creating subroutines.

1. Create a dynamic structure:

Old Code
  DATA: lt_code(100) TYPE c OCCURS 0 WITH HEADER LINE,
        lv_type(100),
        lv_repid LIKE sy-repid,
        lw_fcat TYPE lvc_s_fcat.


* DYNAMISCH TYPES GENEREREN IN PROGRAMMA'S
  lt_code = 'REPORT GENERATE_TYPES.'.
  APPEND lt_code.

  lt_code = 'TYPES: BEGIN OF T_DATA,'.
  APPEND lt_code.

  LOOP AT p_fcattab INTO lw_fcat.
    CONCATENATE lw_fcat-fieldname 

                '(' 
                lw_fcat-intlen 
                ') TYPE c,' 
           INTO lt_code.
    APPEND lt_code.
  ENDLOOP.

  lt_code = 'END OF T_DATA.'.
  APPEND lt_code.

  GENERATE SUBROUTINE POOL lt_code NAME lv_repid.
  CONCATENATE '\PROGRAM=' lv_repid '\TYPE=T_DATA' INTO p_type.



New Code
*&--------------------------------------------------------------*
*&      Form  CREATE_INTERNAL_STRUCTURE

*&--------------------------------------------------------------*
*       Create internal structure
*---------------------------------------------------------------*
FORM CREATE_INTERNAL_STRUCTURE TABLES p_fcattab TYPE lvc_t_fcat
                  CHANGING p_struc TYPE REF TO cl_abap_structdescr
                           p_struc_table TYPE REF TO cl_abap_tabledescr.

  DATA: ls_comp TYPE abap_componentdescr,
        lw_fcat TYPE lvc_s_fcat,
        lt_comp TYPE cl_abap_structdescr=>component_table,
        lv_integer TYPE i.

  LOOP AT p_fcattab INTO lw_fcat.
    ls_comp-name = lw_fcat-fieldname.
    lv_integer = lw_fcat-intlen.
    ls_comp-type = cl_abap_elemdescr=>get_c( lv_integer ).
    APPEND ls_comp TO lt_comp.
  ENDLOOP.

  TRY.
   p_struc = 

           cl_abap_structdescr=>create( p_components = lt_comp ).
  CATCH cx_sy_struct_creation .
  ENDTRY.

  TRY.
    p_struc_table = cl_abap_tabledescr=>create( p_struc ).
    CATCH cx_sy_table_creation .
  ENDTRY.

ENDFORM.                    " CREATE_INTERNAL_STRUCTURE


2. Create a dynamic program

Main Program
  ...
EXPORT <whatever is needed> TO MEMORY ID 'ABC'.
* Execute the code generation logic in new internal mode
SUBMIT <Sub Program> AND RETURN.

Sub Program
  ...
IMPORT <whatever is needed> FROM MEMORY ID 'ABC'.
* Logic to generate the internal table of ABAP code
...
GENERATE SUBROUTINE POOL <codetab> NAME gv_program.
IF SY-SUBRC EQ 0.
PERFORM <generated form> IN PROGRAM (gv_program).
ENDIF.