E1 9.2.3 with 64-bit for client and server

Thanks! And we have a x64 version of OWDLC available to go with it already!
 
Just completed the 64bit upgrade in our lab. I must say it was very smooth, well done Oracle. PatWel tool updates to come.

Craig
 
Since our lab is pretty much pristine, there was no custom stuff to refit. But, there is a massive list of ESUs to apply for 64bit support. Change Assistant has a predefined query to batch up those ESUs.
 
I have heard that custom code may need to be fixed for 64bit. For the life of me I can't think what would need to be fixed. I don't know if I should shrug it off as a few minor things to fix or if this is going to be like the XE to Unicode thing... or worse.
 
I have not messed around with JDE E1 Standalone for years. Do they still provide those? Will there be a 64bit version?
 
Hi Brian,

You can check out the AutoDeploy AllInOne AMI on AWS for JDE -- Run Tools 9.2.3, 64-bit, Orchestrator 7.0.0.0 + All ESU, UDO, and DataPack through 8-Nov-2018

Takes about 10 minutes to spool up a full install. Let me know what you think.

https://amzn.to/2z85oK0
 
One of the things I am interested in is being able to compile C BSFN code. Back during our Xe to 9.0 upgrade, before the upgrade started I was able to use Standalone to fix Unicode issues before the upgrade project actually started so I had a game plan. I want to be able to do the same thing with the 64bit stuff we will need to fix.

BTW, if you go to https://docs.oracle.com/cd/E84502_01/learnjde/64bit.html there is a link to a pdf explaining some of the the possible 64bit issue in C BSFNs.
 
Last edited:
Brian,

You can use that machine image to compile C code. I have a document about the C code changes, and gotchas. Shoot me an email and I'll send it your way.

[email protected]
 
I guess it really depends on what the custom code does. Storing an HREQUEST (or any handle) in a GENLNG DS member would be an issue as the GENLNG is a long (32 bit) and the HREQUEST would now be 64bit. Any casting of pointers to 32bit values (int, long) in order to do arithmetic would now cause truncation. The compiler should catch some things with warnings. I don't have a 64bit porting gig on the radar, but it would cool if we shared issues in a common place. It was mentioned Oracle had a conversion tool, but I haven't been able to find it.
 
Extract from Oracle Docs
JD Edwards EnterpriseOne 64-bit Processing Frequently Asked Questions (Doc ID 2390692.1)

How are customizations impacted if I transition to 64-bit processing?

A: There is no impact to spec-based objects such as interactive applications, batch
applications, named event rules, and other spec-based objects. Customized C business
functions may need to be retrofitted for 64-bit processing. To simplify the retrofitting, Oracle
has delivered an embedded utility to assist with converting customized C business functions
to be 64-bit processing complian
 
How exactly is ID defined?

This is kinda what I have feared for a while now when thinking about 64bit, how Oracle chooses to define ID. I have one very narrow use case that will probably need to be fixed. It will be easy to find and fix I just don't like the fix.

Whenever I pass pointers from/to a BSFN I always use jdeStoreDataPtr/jdeRemoveDataPtr as recommended by Oracle. However, I try to avoid patterns that require it's use (i.e. I try to avoid passing pointers) as much as possible and have very strict rules I try to follow about how I use jdeStoreDataPtr. For example I try to make sure that if I pass a pointer handle it is immediatly retrieved/removed by the callee in one synchronous execution. This also means that I try not to have a situation where I pass a pointer handle back to ER code that requires a later user action to initiate code that retrieves/removes the handle (free's it). In other words I avoid situations that would result in leaving jdeStoreDataPtr handles allocated.

The one flaw with jdeStoreDataPtr is that it only has a small fixed number of handles (1000 I think, maybe 10000) that can be allocated at any one point. The problem with this is that a bug in one little piece of code (ER, C code, or any other binding like BSSV or XML Call Object) that leaks handles can crash the entire user session or even Zombie the Call Object Kernel. Further more, a bug in one application can effect all other applications and it my not be easy to indentify which application has the bug. For example a bug that leaks handles in the PO Reciepts module could cause not only PO Reciepts to crash but also Load Build or General Ledger (any other application that uses jdeStoreDataPtr). This differs from other types of resource leaks which are often localized to the application with the bug. For example a bug that leaks jdeCache cursors in Sales Order Entry won't necessarily break Accounts Payble applications even if Accounts Payable also uses jdeCache and, depending on the jdeCache design pattern, wont necessarily break other running instances of the same application. Additionaly a bug like leaking jdeCache cursor handles may never even manifest itself.

Because of this I have one use case where I intentionally did NOT use jdeStoreDataPtr. Iterating jdeCache records in ER code.

Code:
lpDS->idCursorHandle = (ID)hCursor;
...
hCursor = (HJDECURSOR)lpDS->idCursorHandle;

For starters I initially thought that HJDECURSOR was in fact a true opaque handle and not a memory address so initially I didn't realize I needed to use jdeStoreDataPtr. But beyond that, this is a case where I am generally passing out a cache cursor to ER code as I am iterating through jdeCache to fill a grid or something. With page-at-a-time processing this will, by design, leave cursors open until the end of the list is reached or the user presses find or closes the form, etc. And this is also the most likly use case to contain bugs by the caller that could, if I used jdeStoreDataPtr, leak jdeStoreDataPtr handles.

The recomendation from Oracle is to replace the code above with:

Code:
lpDS->idCursorHandle = jdeStoreDataPtr(hUser, hCursor);
...
hCursor = jdeRemoveDataPtr(hUser, lpDS->idCursorHandle);

My fear is that this could cause bugs to suddenly manifest themselves that were previously, for all intensive purposes, innocuous. And these bugs are going to be EXTREMELY hard to track down.
 
Yeah. That won't work, ID is defined to be "unsigned int" in the new release which is always 32 bit, and HCURSOR is "void *". (ID was "unsigned long" but as their doc points out, long was 32 bits everywhere in 32-bit mode, but in 64-bit enabled code, long is 32 bits on IBMi and windows, and 64 bits on UNIXes).

The thing is, that code of yours already wouldn't have worked on IBMi, as pointers there have always been 16 bytes (128 bits), and you would be truncating all but 32 bits of the pointer on the pre-9.2.3 releases as well.

But I understand your concerns!
 
Last edited:
Very interesting point John, and thanks for that detail. I have been working on an iSeries for years and we have a couple of cases (pre 64bit JDE) where a handle is passed to a function, with no problems. I believe the issue is controlled by the nature of a "handle". It's an opaque pointer, my favourite description. It's not a pointer to any type or structure, and really just a slot in a table of pointers. This abstraction allows the system to manage the true size of the memory being pointed to. In fact, Windows stores handles to shared resources as 32bit values even in a 64bit OS (i.e. the first 32 bits are set to 0 in 64bit). Oracle is probably following the same pattern.

Here's something to think about … you can declare a JDE variable as a "handle" to be used in table IO within an NER. That variable is declared as an ID (32 bit). The underlying code that opens the table/view stores the handle in the ID variable. I think the JDE API is ensuring these handle values are 32bit, just 0 filled in a 64bit arch.

Craig
 
That's an interesting observation. So it could be that I could safely cast from HJDECURSOR to ID and back in a 64bit arch if HJDECURSOR is returning a handle using the same technique as HREQUEST i.e. a 32 bit value?
 
We can infer that is the case with the HREQUEST handle since generated NER stores the value in an ID. We can hope that the same holds true for all handles. Perhaps I'll create a test function that opens thousands of cursors and checks the status of the high 32 bits.
 
We can infer that is the case with the HREQUEST handle since generated NER stores the value in an ID. We can hope that the same holds true for all handles. Perhaps I'll create a test function that opens thousands of cursors and checks the status of the high 32 bits.

Can you provide an example of this (a JDE NER file name/function/line)? All generated NERs I've looked at looking for this so far are using HREQUESTS and not IDs.
 
This is from TR9.1 (32bit). It does look like maybe the actual HREQUEST is still stored in an HREQUEST variable (FILEIO_HANDLE_INFO zHndlInfo) and evt_HandleF0101 is a true handle to zHndInfo????

ER Code
Code:
=======================================================================
     NAMED ER: zztest_TestTableHandle
=======================================================================
     evt_HandleF0101
     evt_mnAddressNumber
     evt_szNameAlpha
     OPT: Using Defaults
0001 VA evt_mnAddressNumber = "2000072"
0002 VA evt_HandleF0101 = F0101.Open Handle
0003 F0101(VA evt_HandleF0101).Fetch Single
        VA evt_mnAddressNumber =  TK Address Number
        VA evt_szNameAlpha <- TK Name - Alpha
0004 F0101(VA evt_HandleF0101).Close


Generated C code
Code:
JDEBFRTN(ID) JDEBFWINAPI
zztest_TestTableHandle( LPBHVRCOM lpBhvrCom ,
    LPVOID lpVoid ,
    LPDSD58DUMMY lpDS )
{
  /*****************************************************************
   *  Variable declarations
   *****************************************************************/
  ID idRtnVal = ER_SUCCESS;
  ID evt_HandleF0101 = 0;
  MATH_NUMERIC evt_mnAddressNumber = { 0 };
  JCHAR evt_szNameAlpha[41] = { 0 };
  JDEDB_RESULT iRtnJDB = JDEDB_ERROR;

  /*****************************************************************
   *  Declare structures
   *****************************************************************/
  F0101 zF0101_3 = { 0 };
  FILEIO_HANDLE_INFO zHndlInfo = { 0 };
  SELECTSTRUCT zSelect4[1] = { 0 };
  DBREF zDbRef5 = { 0 };

  /*****************************************************************
   *  Declare pointers
   *****************************************************************/
  LPJDEAPP lpObj = (LPJDEAPP)NULL;
  LPAPPVARIABLES pAppVars = (LPAPPVARIABLES)NULL;
  HENV hEnv = (HENV)NULL;
  JCHAR* pszEnvName = (JCHAR*)NULL;
  HUSER hUser = (HUSER)NULL;
  LPKEYINFO pKeyInfo = (LPKEYINFO)NULL;
  void* pKeyBuffer = NULL;

  /*****************************************************************
   *  Check for NULL pointers
   *****************************************************************/
  if ( ( lpBhvrCom == (LPBHVRCOM)NULL ) ||
      ( lpVoid == (LPVOID)NULL ) ||
      ( lpDS == (LPDSD58DUMMY)NULL ) )
  {
    jdeErrorSet( lpBhvrCom , lpVoid , 0L , _J("4363") , (LPVOID)NULL );
    return ER_ERROR;
  }

  /*****************************************************************
   *  Set pointers
   *****************************************************************/
  lpObj = lpBhvrCom->lpObj;
  pAppVars = lpObj->lpzAppVars;
  hEnv = lpBhvrCom->hEnv;
  pszEnvName = JDB_GetEnvironment( hEnv );
  iRtnJDB = JDB_InitBhvr( lpBhvrCom , &hUser , NULL , JDEDB_COMMIT_AUTO );

  /*****************************************************************
   *  Main processing
   *****************************************************************/
  zDbRef5.idInstance = 0L;

  /* VA evt_mnAddressNumber = "2000072" */
  ParseNumericStringEx( &evt_mnAddressNumber ,
      _J("2000072") , DEFAULT_SEPARATOR | CURRENCY_KEEP );

  /* VA evt_HandleF0101 = F0101.Open Handle */
  pAppVars->iTableRetCode = RTK_CER_FIOOpenHandle( hEnv, hUser ,
      _J("F0101") , pszEnvName , 1L ,  0 , &evt_HandleF0101 );

  /* F0101(VA evt_HandleF0101).Fetch Single */
  pKeyInfo = (LPKEYINFO)jdeAlloc(COMMON_POOL, 3 * sizeof(struct keyinfo), MEM_ZEROINIT);
  if ( RTK_CER_FIOGetHandleInfo( evt_HandleF0101 , &zHndlInfo ) )
  {
    pAppVars->iTableRetCode = ER_ERROR;
    if ( JDB_ClearSelection( zHndlInfo.hReqest ) == JDEDB_PASSED )
    {
      RTK_CER_FIOSelectInitH( zSelect4 , 1 , zHndlInfo.nType ,
          zHndlInfo.szFileName , 0L );
      jdeNIDcpy( zSelect4[0].Item1.szDict , _J("AN8") );
      if ( zHndlInfo.nType == FILEIO_TYPE_VIEW )
      {
        jdeNIDcpy( zSelect4[0].Item1.szTable , _J("F0101") );
        zSelect4[0].Item1.idInstance = 0L;
      }
      zSelect4[0].lpValue = (LPVOID)&evt_mnAddressNumber;
      jdeNIDcpy( zDbRef5.szTable , zHndlInfo.szFileName );
      jdeNIDcpy( zDbRef5.szDict , _J("AN8") );
      if(jdeK2AddtoKeyStruct(pKeyInfo, 0, zDbRef5, &evt_mnAddressNumber, 9, -1) == FALSE)
      {
        if(pKeyInfo)
        {
          jdeFree(pKeyInfo);
          pKeyInfo=NULL;
        }
      }
      if(pKeyInfo)
      {
        pKeyBuffer=JDB_BuildKeyBuffer(pKeyInfo,1);
        if ( JDB_FetchKeyed( zHndlInfo.hReqest , 1L , pKeyBuffer , 1, &zF0101_3 , 0 ) != JDEDB_PASSED )
        {
          JDB_ClearSelection( zHndlInfo.hReqest );
          JDB_ClearSequencing( zHndlInfo.hReqest );
        }
        else
        {
          jdeStrncpyTerminate( evt_szNameAlpha , zF0101_3.abalph ,
              DIM( evt_szNameAlpha ) );
          pAppVars->iTableRetCode = ER_SUCCESS;
        }
      }
      else
      {
        RTK_CER_FIOSelect( zHndlInfo.hReqest , 1L , 1 , zSelect4 , 
            &pAppVars->iTableRetCode );
        if ( pAppVars->iTableRetCode == ER_SUCCESS )
        {
          pAppVars->iTableRetCode = ER_ERROR;
          if ( JDB_Fetch( zHndlInfo.hReqest , &zF0101_3 , 0 ) != JDEDB_PASSED )
          {
            JDB_ClearSelection( zHndlInfo.hReqest );
            JDB_ClearSequencing( zHndlInfo.hReqest );
          }
          else
          {
            jdeStrncpyTerminate( evt_szNameAlpha , zF0101_3.abalph ,
                DIM( evt_szNameAlpha ) );
            pAppVars->iTableRetCode = ER_SUCCESS;
          }
        }
      }
    }
  }
  if ( pKeyInfo )
  {
    jdeFree( pKeyInfo );
    pKeyInfo=(LPKEYINFO)NULL;
  }
  if ( pKeyBuffer )
  {
    JDB_FreeKeyBuffer( pKeyBuffer );
    pKeyBuffer=NULL;
  }

  /* F0101(VA evt_HandleF0101).Close */
  pAppVars->iTableRetCode = RTK_CER_FIOCloseHandle( evt_HandleF0101 );
  pAppVars->iTableRetCode = RTK_CER_FIOCloseHandle( evt_HandleF0101 );
  if ( hUser ) { JDB_FreeBhvr( hUser ); }

  return idRtnVal;
} /* end of zztest_TestTableHandle */

Code:
typedef struct tagFILEIO_HANDLE_INFO
{
   HENV           hEnv;          /* environment associated with handle  */
   NID            szEnvName;     /* environment name                    */
   HUSER          hUSER;         /* user associated with handle         */
   NID            szFileName;    /* filename handle points to           */
   unsigned short nType;         /* 0/1 = table/view                    */
   unsigned long  nHandleValue;  /* Handle value                        */
   HREQUEST       hReqest;       /* the HREQUEST for this fileio handle */
} FILEIO_HANDLE_INFO;
 
Back
Top