Monday, 3 October 2011

X++ select statements in IL code

I doubt this will be of much use in the real-world, but I was curious as to how X++ select statements are translated into IL code. There's obviously no direct translation from an X++ select to C# code (except possibly with LINQ but it would be almost impossible to match the query behaviour exactly).

Compiling the following X++ code:

private void simpleSelect()
    SalesLine                   salesLine;
    str                         inventTransID;

    // Basic selection
    select firstonly salesLine
        order by InventTransId desc
        where   salesLine.RecId != 0;

    InventTransId = salesLine.InventTransId;

Gives us the following C# (Extracted from the compiled DLL using RedGate Reflector):

public override void Simpleselect()
    SalesLine salesLine = new SalesLine();
    string inventTransID = PredefinedFunctions.GetNullString();
    SalesLine table = salesLine;
    FieldList fieldList = new FieldList();
    fieldList.Add(0x1a, 0);
    int o = 0;
    PredefinedFunctions.Where(PredefinedFunctions.newBinNode(PredefinedFunctions.newFieldExpr(salesLine, 0xfffe), new valueNode(o), 0x13), table);
    inventTransID = salesLine.InventTransId;

Not the friendliest looking code is it? Basically, it's building up an object model representing the select statement. I presume this is similar to using the QueryBuild classes, although it looks like a completely different API.

And a more complicated example with joins, in X++:

private void complexSelect()
    InventTable                 inventTable;
    InventTrans                 inventTrans;
    InventTransOriginSalesLine  inventTransOrigin;
    SalesLine                   salesLine;
    Amount                      amount;

    select firstonly salesLine
        order by InventTransId desc
    join inventTransOrigin
        where   inventTransOrigin.SalesLineInventTransId    == salesLine.InventTransId
    join inventTrans
        where   inventTrans.InventTransOrigin               == inventTransOrigin.RecId;

    amount = salesLine.LineAmount;


Gives us:

public override void Complexselect()
    InventTable inventTable = new InventTable();
    InventTrans inventTrans = new InventTrans();
    InventTransOriginSalesLine inventTransOrigin = new InventTransOriginSalesLine();
    SalesLine salesLine = new SalesLine();
    SalesLine joinParent = salesLine;
    FieldList fieldList = new FieldList();
    fieldList.Add(0x1a, 0);
    InventTransOriginSalesLine table = inventTransOrigin;
    table.Join(0, joinParent, 0xba7);
    PredefinedFunctions.Where(PredefinedFunctions.newBinNode(PredefinedFunctions.newFieldExpr(inventTransOrigin, 2), PredefinedFunctions.newFieldExpr(salesLine, 0x1a), 0x12), table);
    InventTrans trans = inventTrans;
    trans.Join(0, table, 0xb1);
    PredefinedFunctions.Where(PredefinedFunctions.newBinNode(PredefinedFunctions.newFieldExpr(inventTrans, 0x44), PredefinedFunctions.newFieldExpr(inventTransOrigin, 0xfffe), 0x12), trans);
    decimal amount = salesLine.LineAmount;

The hex-values refer to the object numbers of the table/fields being referenced. eg 0x167 in the call to table.Find is 359 in decimal, which is the table ID of SalesLine.
The actual work is still carried out in native Kernel code (AxServ32.exe) - The compiled DLL links to the executable and calls it via interop.
Interesting? A little bit.. Useful? Not really.

More practical posts to follow.

No comments:

Post a Comment