Friday, November 16, 2012

A T-SQL Script That Lists Navigations For Component

How to find navigation paths for a PeopleSoft component has been a question frequently asked and there are already quite a few posts on Internet discussing about this. For example, you can visit here or here for some useful SQL scripts that can do this. However, these SQLs are written for Oracle and can't be used for MS SQL Server because they make use of an Oracle specific function SYS_CONNECT_BY_PATH() which is not implemented in MSSQL.


Recently I created a script using T-SQL, as requested by my colleagues who are working on MSSQL 2008. This script supports two search mode:

  • Search by Component Name. Assigning a component name to @COMP_NAME, the script will list out all navigation paths for that component. For example
     declare @COMP_NAME as nvarchar(18) = 'USERMAINT';

          Output will be

      Component: USERMAINT
      Menu Path: PeopleTools > Security > User Profiles > User Profiles

  • Search by Component Label. Assigning a component navigation label to@COMP_LABEL, the script will list our all components with the particular lable. For example
           declare @COMP_LABEL as nvarchar(30) = 'User Profiles';

           Output will be

      Component: USERMAINT 
      Menu Path: PeopleTools > Security > User Profiles > User Profiles
      Component: DSUSRPROF2 
      Menu Path: Enterprise Components > Directory Interface > Mappings > User Profiles          

           If 'Y' is set for @IGNORE_CASE you can even search for label without worrying about case sensitivity.

           The script is as follows:


/******************************************************************************
 Filename   : FIND_MENUPATHS.SQL
 Version    : 1.0
 Description: This script query PeopleSoft table PSPRSMDEFN to find out menu
              paths for a component
 Author     : devwfb@gmail.com
 Date       : 08 NOV 2012
 ******************************************************************************/

--
-- Parameters
--
--=============================================================================
-- QUERY MODE 1 - By Component
declare @COMP_NAME as nvarchar(18) = '';
--=============================================================================
-- QUERY MODE 2 - By Label
declare @COMP_LABEL as nvarchar(30) = '';
declare @IGNORE_CASE as nvarchar(1) = 'Y';

--
-- Constants & Variables
--
declare @PORTAL_NAME as nvarchar(30) = 'EMPLOYEE';
declare @SEP as nvarchar(3) = '>';
declare @component_name as nvarchar(30);
declare @prev_component as nvarchar(30) = '';
declare @portal_label as nvarchar(30);
declare @menu_path as nvarchar(max);
declare @parent_obj as nvarchar(30);

--
-- Verification for parameters
--
set @COMP_NAME = ltrim(rtrim(@COMP_NAME));
set @COMP_LABEL = ltrim(rtrim(@COMP_LABEL));
if @COMP_NAME = '' and @COMP_LABEL = '' 
begin
 print 'Alert: Please provide parameter Component Name or Component Label';
 return
end
else if @COMP_NAME <> '' and @COMP_LABEL <> '' 
begin
 print 'Alert: Component Name and Component Label are mutually exclusive. Please provide only one parameter';
 return
end

--
-- Search menu paths
--
if @COMP_NAME <> ''
 -- Mode 1
 declare cur_navi cursor for
  select PORTAL_PRNTOBJNAME, 
      PORTAL_LABEL,
      PORTAL_URI_SEG2
    from PSPRSMDEFN
   where PORTAL_NAME = @PORTAL_NAME
     and PORTAL_CREF_URLT = 'UPGE'
     and (PORTAL_URI_SEG2 = @COMP_NAME or PORTAL_URI_SEG2 like @COMP_NAME);
else if @IGNORE_CASE = 'Y'
 declare cur_navi cursor for
  select PORTAL_PRNTOBJNAME, 
      PORTAL_LABEL,
      PORTAL_URI_SEG2
    from PSPRSMDEFN
   where PORTAL_NAME = @PORTAL_NAME
     and PORTAL_CREF_URLT = 'UPGE'
     and (upper(PORTAL_LABEL) = upper(@COMP_LABEL) or upper(PORTAL_LABEL) like upper(@COMP_LABEL));
else
 declare cur_navi cursor for
  select PORTAL_PRNTOBJNAME, 
      PORTAL_LABEL,
      PORTAL_URI_SEG2
    from PSPRSMDEFN
   where PORTAL_NAME = @PORTAL_NAME
     and PORTAL_CREF_URLT = 'UPGE'
     and (PORTAL_LABEL = @COMP_LABEL or PORTAL_LABEL like @COMP_LABEL);
open cur_navi
fetch next from cur_navi into @parent_obj, @portal_label, @component_name
if @@fetch_status <> 0
begin
 close cur_navi
 deallocate cur_navi
 print 'No menu paths found matching given parameter.'
 return
end
while @@fetch_status = 0
begin
 set @menu_path = @portal_label;
 while 1=1
 begin
  select @parent_obj = PORTAL_PRNTOBJNAME, 
      @portal_label = PORTAL_LABEL
    from PSPRSMDEFN
   where PORTAL_NAME = @PORTAL_NAME
     and PORTAL_OBJNAME <> PORTAL_PRNTOBJNAME
     and PORTAL_OBJNAME = @parent_obj;
  if @parent_obj is null or @portal_label = 'Root' break;
  set @menu_path = @portal_label + ' ' + @SEP + ' ' + @menu_path
 end 
 if @component_name <> @prev_component 
 begin 
  print ''
  print 'Component: ' + @component_name;
  set @prev_component = @component_name;
 end
 print 'Menu Path: ' + @menu_path;
 fetch next from cur_navi into @parent_obj, @portal_label, @component_name
end
close cur_navi
deallocate cur_navi

Tuesday, October 5, 2010

Calculate Database Connections Needed For A PeopleSoft Instance

As a PeopleSoft system administrator or a DBA, chance may be you need to calculate how many database connections are needed for a PeopleSoft database. Below are some tips for the calculation:-

App Server Domain

  • The following processes connect to the database: PSMONITORSRV, PSANALYTICSRV, PSSAMSRV, PSQRYSRV, PSAPPSRV, PSQCKSRV, PSBRKDSP, PSBRKHND, PSPUBDSP, PSPUBHND, PSSUBDSP, PSSUBHND, PSMCFLOG, PSUQSRV, PSRENSRV (Tip: in psappsrv.ubb, all processes except for PSWATCHSRV with -D parameter connect to the database)

  • One PSAPPSRV can have 2 db connections if DbFlags is not set to 4(Disable Second DB Connection) or 8(Disable Persistent Secondary DB Connection)

  • The following processes don't connect to the database: BBL, JSL, JSH, WSL, WSH, PSDBGSRV, JREPSVR, PSWATCHSRV


Process server domain


  • The following processes connect to the database: PSPRCSRV, PSAESRV, PSDSTSRV, PSMSTPRC, PSMONITORSRV (Tip: in psprcsrv.ubb, all processes with -CD parameter connect to the database)

  • One PSAESRV can have 2 db connections if DbFlags is not set to 4(Disable Second DB Connection) or 8(Disable Persistent Secondary DB Connection)

  • The following processes don't connect to the database: BBL



Others
  • External programs, such as PSRUN (cobol remote call), PSCRRUN.exe(Crystal Reports), PSSQR(SQR report), PSNVS(nVision) etc, also need db connection

  • Tools/applications used by developers/system administrators, such as pside.exe, psdmt.exe, Oracle client, etc, also need db connection

Wednesday, July 14, 2010

Quickly Reconfigure App/Process Server Domain

PeopleSoft system administrators rely on psadmin to reconfigure the application or process server domain. We all have experience of having to go through all the configuration items from psadmin option 14, just to turn on/off one process (let's say, pub/sub server). Actually this is not necessary if you have an understanding of where the configuration items stay - you can bypass psadmin and manually modify those configurations quickly.

All items configurable from psadmin are saved in 3 different files for each server domain:
  • For application server: psappsrv.ubb, psappsrv.ubx and psappsrv.cfg.
  • For process server: psprcsrv.ubb, psprcsrv.ubx and psprcs.cfg.
For example, your app server domain's pub/sub server is currently off and you want ti turn it on, you can do the following:

1) Shutdown the server domain first - this is a must
2) (This is no more needed, as UBB file is generated using UBX as a template.)


Open psappsrv.ubb, scroll down to the bottom, you will find two lines under 'ubbgen control values:'

# [ 6]: {PUBSUB}: FALSE
# [ 7]: {!PUBSUB}: TRUE
Swap the FALSE and TRUE so the 2 lines appear as below and save/close the file.
# [ 6]: {PUBSUB}: TRUE
# [ 7]: {!PUBSUB}: FALSE

3) Open psappsrv.ubx, search '*PS_DEFINES', under this line you will see

{PUBSUB} Do you want the Publish/Subscribe servers configured (y/n)? [n]:
Change [n] to [y] and save/close the file.

4) Reconfigure - psadmin -c reconfigure -d DOMAIN
5) Restart - psadmin -c boot -d DOMAIN

You will see PUB/SUB server processes are running now.

You can manipulate process server configurations similarly.

Be sure to make a backup of the files before you try with this.

Update:
- 18 Mar 2011: Remote point 2) as it is an unnecessary step.

Monday, November 9, 2009

Make It Easy To Check User's Accessibility To PS Queries

In PeopleSoft, checking whether a user has access to a PS Query is sometime a very frustrating job, particularly when the query has references to many base records which are added into multiple access groups in different query trees, and these query trees and access groups are granted to different permission lists which are owned by different roles.

Unfortunately, I am the guy who have always been asked 'How come I am not able to view/edit query ... blah blah...' and I have spent too much time and efforts on this. Yesterday I eventually decided something must be done to pull me out of this repetitive and monotonous job, so I wrote the PL/SQL script chk_query_access.sql.

This script asks for 3 parameters:

1) PS Query Name: wildcards (%, _) are accepted. Escape character '\' is allowed too. For example, you can type in full query name N_Q006_SR_LOA, or you can also type in a query name pattern N\_Q00_\_% to check accessibility for queries N_Q001 to N_Q009.

2) User ID: is case-sensitive

3) Verbose Level: ranges from 0 - 3
  • Level 0: only shows query grant status. This is the default level.

SQL> @d:\SQL\chk_query_access.sql
SQL> SET ECHO OFF
Query Name (wilecard accepted): N_Q006_SR_LOA
User ID: PSTEST
Verbose Level:
0 - Show query grant status (default)
1 - Show query/record grant status
2 - Show query/record grant status and grant paths
3 - Show query/record grant status and all paths
Your Choice(0,1,2,3):
old 5: v_qryname_pattern PSQRYDEFN.QRYNAME%TYPE := trim('&prompt_qryname');
new 5: v_qryname_pattern PSQRYDEFN.QRYNAME%TYPE := trim('N_Q006_SR_LOA');
old 6: v_oprid PSOPRDEFN.OPRID%TYPE := trim('&prompt_oprid');
new 6: v_oprid PSOPRDEFN.OPRID%TYPE := trim('PSTEST');
old 7: v_verbose_lvl INTEGER := &prompt_verbose;
new 7: v_verbose_lvl INTEGER := 0;
===========================================================
=== Checking User(PSTEST)'s access to query 'N_Q006_SR_LOA'
===
===
=== Query 'N_Q006_SR_LOA' granted to 'PSTEST'
===

PL/SQL procedure successfully completed.
  • Level 1: shows query grant status and record grant status. This is useful when you want to know what record is not granted if the query is not accessible.
...
...
...
===========================================================
=== Checking User(PSTEST)'s access to query 'N_Q006_SR_LOA'
===
-----------------------------------------------------------
>>> Record 1: N_STNT_PERS_VW
>>> Record granted
-----------------------------------------------------------
>>> Record 2: N_STNT_SUMAC_VW
>>> Record not granted
-----------------------------------------------------------
>>> Record 3: N_LOA
>>> Record granted
===
=== Query 'N_Q006_SR_LOA' not granted to 'PSTEST'
===

...

  • Level 2: show query grant status, record grant status, and grant path. At this level the script also shows the whole grant path, eg Record - Query Tree/Access Group - Permission List - Role - User Profile.

...
...
...
===========================================================
=== Checking User(PSTEST)'s access to query 'N_Q006_SR_LOA'
===
-----------------------------------------------------------
>>> Record 1: N_STNT_PERS_VW
[Y] N_QUERY_TREE_RPT.N_RPTQAG_MOD_RANK -> N_R030_SR_MODULE_RANKING -> N_EXAM_QRY_EU -> PSTEST
[Y] N_QUERY_TREE_RPT.N_RPTQAG_BOE_ATTACH -> N_R031_SR_BOE_ATTACHMENTS -> N_EXAM_QRY_EU -> PSTEST
>>> Record granted
-----------------------------------------------------------
>>> Record 2: N_STNT_SUMAC_VW
>>> Record not granted
-----------------------------------------------------------
>>> Record 3: N_LOA
[Y] N_QUERY_TREE_DEN.N_DNQAG_LOA -> N_PROG_PLAN_ADMIN_QRY_EU -> N_PROG_PLAN_ADMIN_QRY_EU -> PSTEST
[Y] N_QUERY_TREE_DEN.N_DNQAG_LOA -> N_PROG_PLAN_ADMIN_QRY_IT -> N_PROG_PLAN_ADMIN_QRY_IT -> PSTEST
[Y] N_QUERY_TREE_RPT.N_RPTQAG_BOE_ATTACH -> N_R031_SR_BOE_ATTACHMENTS -> N_EXAM_QRY_EU -> PSTEST
>>> Record granted
===
=== Query 'N_Q006_SR_LOA' not granted to 'PSTEST'
===
...
  • Level 3: the most detailed verbose, especially useful when a query is not accessible and you need to find out at what position the granting is not done.

...
...
...
===========================================================
=== Checking User(PSTEST)'s access to query 'N_Q006_SR_LOA'
===
-----------------------------------------------------------
>>> Record 1: N_STNT_PERS_VW
[Y] N_QUERY_TREE_RPT.N_RPTQAG_MOD_RANK -> N_R030_SR_MODULE_RANKING -> N_EXAM_QRY_EU -> PSTEST
[Y] N_QUERY_TREE_RPT.N_RPTQAG_BOE_ATTACH -> N_R031_SR_BOE_ATTACHMENTS -> N_EXAM_QRY_EU -> PSTEST
>>> Record granted
-----------------------------------------------------------
>>> Record 2: N_STNT_SUMAC_VW
[N] N_QUERY_TREE_RPT.N_RPTQAG_MOD_RANK -> N_R030_SR_MODULE_RANKING -> N_EXAM_QRY_EU
[N] N_QUERY_TREE_RPT.N_ROGQAG_ENRL_STATS2 -> N_R042_SR_ENROL_STATS2
>>> Record granted
-----------------------------------------------------------
>>> Record 3: N_LOA
[Y] N_QUERY_TREE_DEN.N_DNQAG_LOA -> N_PROG_PLAN_ADMIN_QRY_EU -> N_PROG_PLAN_ADMIN_QRY_EU -> PSTEST
[Y] N_QUERY_TREE_DEN.N_DNQAG_LOA -> N_PROG_PLAN_ADMIN_QRY_IT -> N_PROG_PLAN_ADMIN_QRY_IT -> PSTEST
[Y] N_QUERY_TREE_RPT.N_RPTQAG_BOE_ATTACH -> N_R031_SR_BOE_ATTACHMENTS -> N_EXAM_QRY_EU -> PSTEST
>>> Record granted
===
=== Query 'N_Q006_SR_LOA' granted to 'PSTEST'
===


Updates:
  • 18-Nov-2009: Added check for defnition security.
  • 24-Nov-2009: Added support for command line arguments. Added access group cascading check.

Wednesday, November 4, 2009

Script Analyzing TraceSQL File And Extracting SQL Statements

TraceSQL is a great tool for Peoplesoft development debugging and application troubleshooting. But TraceSQL file only logs SQL statements and SQL variable values separately and so is less readable and hard to re-run.

This script is developed to analyze TraceSQL files, filter out unnecessary information, extract SQL statements and replace all SQL variables with the actual values.

For example, for the following contents in a tracesql file:


PSAPPSRV.12271 (951) 1-190 20.22.39 0.008245 Cur#1.12271.CS90SUP RC=0 Dur=0.000238 COM Stmt=SELECT OBJNAME, FLAG, PTCUSTOMFORMAT FROM PSUSEROBJTYPE WHERE MENUNAME = :1 AND PNLGRPNAME = :2 AND PNLNAME = :3 AND OPRID = :4 AND FIELDTYPE = :5
PSAPPSRV.12271 (951) 1-191 20.22.39 0.000013 Cur#1.12271.CS90SUP RC=0 Dur=0.000001 Bind-1 type=2 length=26 value=CALCULATE_TUITION_AND_FEES
PSAPPSRV.12271 (951) 1-192 20.22.39 0.000008 Cur#1.12271.CS90SUP RC=0 Dur=0.000000 Bind-2 type=2 length=14 value=ADJ_TERM_PANEL
PSAPPSRV.12271 (951) 1-193 20.22.39 0.000008 Cur#1.12271.CS90SUP RC=0 Dur=0.000001 Bind-3 type=2 length=1 value=
PSAPPSRV.12271 (951) 1-194 20.22.39 0.000006 Cur#1.12271.CS90SUP RC=0 Dur=0.000000 Bind-4 type=2 length=2 value=PS
PSAPPSRV.12271 (951) 1-195 20.22.39 0.000010 Cur#1.12271.CS90SUP RC=0 Dur=0.000000 Bind-5 type=18 length=2 value=-1

the script comes out with below SQL:


SELECT OBJNAME, FLAG, PTCUSTOMFORMAT FROM PSUSEROBJTYPE WHERE MENUNAME = 'CALCULATE_TUITION_AND_FEES' AND PNLGRPNAME = 'ADJ_TERM_PANEL' AND PNLNAME = ' ' AND OPRID = 'PS' AND FIELDTYPE = -1;


Script usage: xsql /path/to/tracesql

Update:
- 03-Mar-2010: Bug fix: encapsulated date/time values with quotes. Fixed the issue that the last SQL statement is not outputed.

Friday, October 2, 2009

Enhancements To The Scripts Listing Processes and Memory Usage of PeopleSoft Application Server and Process Scheduler

In the post released in February I introduced a script that is able to list all processes of a Peoplesoft app server/process scheduler as well as each process' memory usage information.

I have enhanced this script with the following new features:

- For Peoplesoft App Server & Process Scheduler:

= When -m is specified, the script will print CPU usage percentage aside from memory usage.


$ ~/bin/pl -cmh DOMAIN
PID PROCESS VSIZE(m) RSS(m) CPU%
--- ------- -------- ------ ----
7744 PSBRKHND 104.6 48.3 0.0
27887 PSAPPSRV 585.0 401.7 0.8
7799 PSPUBHND 100.7 24.6 0.0
7685 BBL 11.6 3.9 0.0
7704 PSSAMSRV 98.2 19.6 0.0
7796 PSBRKDSP 108.6 51.8 0.0
7802 PSPUBDSP 332.7 61.8 0.1
9122 JREPSVR 9.5 1.0 0.0
9055 JSL(9050) 11.0 1.9 0.0
8030 PSSUBHND 100.6 19.7 0.0
8350 PSSUBDSP 108.6 49.1 0.0
20335 PSAPPSRV 986.7 803.7 0.7
20562 PSAPPSRV 962.3 712.4 1.0
15765 PSAPPSRV 1006.4 805.3 0.5
13737 PSAPPSRV 188.0 157.3 0.8
6362 PSMONITORSRV 103.3 75.6 0.0
21579 PSWATCHSRV 14.6 8.2 0.0
9114 JSH(9053) 52.6 21.1 0.0
9089 JSH(9051) 44.6 16.8 0.1
9107 JSH(9052) 36.6 21.0 0.0



= When -s is specified, the script will print statistical information on the bottom.


$ ~/bin/pl -cmhs DOMAIN
PID PROCESS VSIZE(m) RSS(m) CPU%
--- ------- -------- ------ ----
7744 PSBRKHND 104.6 48.3 0.0
27887 PSAPPSRV 585.0 401.7 0.1
7799 PSPUBHND 100.7 24.6 0.0
7685 BBL 11.6 3.9 0.0
7704 PSSAMSRV 98.2 19.6 0.0
7796 PSBRKDSP 108.6 51.8 0.0
7802 PSPUBDSP 332.7 61.8 0.1
9122 JREPSVR 9.5 1.0 0.0
9055 JSL(9050) 11.0 1.9 0.0
8030 PSSUBHND 100.6 19.7 0.0
8350 PSSUBDSP 108.6 49.1 0.0
20335 PSAPPSRV 986.7 803.7 0.2
20562 PSAPPSRV 962.3 712.4 0.1
15765 PSAPPSRV 1006.4 805.3 0.3
13737 PSAPPSRV 188.0 157.3 0.1
6362 PSMONITORSRV 103.3 75.6 0.0
21579 PSWATCHSRV 14.6 8.2 0.0
9114 JSH(9053) 52.6 21.1 0.0
9089 JSH(9051) 44.6 16.8 0.1
9107 JSH(9052) 36.6 21.0 0.0
--- ------- -------- ------ ----
17 SERVER 4832.3 3245.7 0.9
5 PSAPPSRV 3728.4 2880.3 0.8
3 CLIENT 133.8 59.0 0.1


= For app server, ports opened by JSL/JSH/WSL/WSH will be printed.

See above example.


= When -r is specified, the script will print the summary memory and CPU usage of processes of all app servers/process schedulers running on the server. This is useful when you need to monitor server's performance. Actually Oracle recommends that the total resident memory for the entire PS Processes not exceed 70 percent of the total real memory available on the server.


$ ~/bin/pl -r
CATEGORY COUNT VSIZE(m) RSS(m) RSS% CPU%
-------- ----- --------- ------ ---- ----
All 98 37598.7 19232.7 29.3 1.7
PSAPPSRV 28 26224.3 15047.6 22.9 1.1
PSAESRV 0 0.0 0.0 0.0 0.0


- For Peoplesoft Web Server: the script now can print some configuration information and running information (memory and CPU usage) of a web domain.


$ ~/bin/pl -w webdomain
DOMAIN: webdomain
TYPE: Single Server
WEBSITES: server1, server2
HEAP SIZE: -Xms512m -Xmx512m -XX:MaxPermSize=256m
SERVER: PIA
HTTP: 8080
HTTPS: 8843 enabled
PID: 19098
RESOURCES: VSIZE=893.8m RSS=700.4m CPU=0.2%


The help message:


Usage 1: list process info for a app server and/or a prcs server
pl [-f] -c|p [-m -h] [-s]

Options:
-f force execution even appserv domain doesn't exsit
-c print processes of application server
-p print processes of process scheduler
-m print memory usage (virtual memory and RSS) and CPU usage(%)
-h print memory usage in human readable format
-s print summary and statistical info

Usage 2: calculate RAM/CPU usage of all app/prcs processes
pl -r

Usage 3: list setting and running info from a web domain (Weblogic only)
pl -w






Currently only Solaris version of the script is available. You can get it from here.


Update on 13-Oct-2009: Some bug fixes. pl -w produces more information.

Wednesday, May 6, 2009

Manipulating Child Rows in A PeopleSoft Component Through Web Services

I had this issue when trying to manipulate ID types for a user profile through web service. It was easy to update an existing ID type or to insert a non-existing ID type. For example, look at the following SOAP message:


<soapenv:Body>
<ns1:Update__CompIntfc__USER_PROFILE xmlns:ns1="http://xmlns.oracle.com/Enterprise/Tools/schemas/M274199.V1">
<ns1:UserID>COPYUSER2</ns1:UserID>
<ns1:IDTypes>
<ns1:IDType>EMP</ns1:IDType>
<ns1:Attributes>
<ns1:Fieldname>EmplID</ns1:Fieldname>
<ns1:Recname>PERSONAL_DATA</ns1:Recname>
<ns1:AttributeValue>AA0001</ns1:AttributeValue>
<ns1:AttributeName>EmplID</ns1:AttributeName>
</ns1:Attributes>
</ns1:IDTypes>
</ns1:Update__CompIntfc__USER_PROFILE>
</soapenv:Body>


If ID Type 'EMP' exists for user profile 'TESTUSER', system updates the ID Type's attribute value as 'AA0001'. Or if ID Type 'EMP' doesn't exist with user profile 'TESTUSER', it inserted.

However, this way won't work if we need to remove 'EMP' from 'TESTUSER'. We must adopt an attribute 'CINodeAction' to do the work:


<soapenv:Body>
<ns1:Update__CompIntfc__USER_PROFILE xmlns:ns1="http://xmlns.oracle.com/Enterprise/Tools/schemas/M274199.V1">
<ns1:UserID>TESTUSER</ns1:UserID>
<ns1:IDTypes CINodeAction="delete">
<ns1:IDType>EMP</ns1:IDType>
</ns1:IDTypes>
</ns1:Update__CompIntfc__USER_PROFILE>

As the matter of fact, we can also set value 'update' or 'insert' to 'CINodeAction' for first and second scenacios stated above, and this makes the SOAP message unambiguous and more understandable.

Attribute 'CINodeAction' is not documented, but can be digged from application package SOAPTOCI.

PS: This tip applies up to PeopleTools 8.49. In to-be-released PeppleTools 8.50, property 'action' has been announced together with some other properties.