Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] InternalExecutionError when running getSObjectRows method #1339

Closed
RonanWilliams1 opened this issue Jan 31, 2024 · 2 comments
Closed
Labels
BUG P3 Rarely Malfunction duplicate This issue or pull request already exists SFGE Issues related to the Salesforce Graph Engine

Comments

@RonanWilliams1
Copy link

Description:

Graph Engine identified your source and sink, but you must manually verify that you have a sanitizer in this path. Then, add an engine directive to skip the path. Next, create a Github issue for the Code Analyzer team that includes the error and stack trace. After we fix this issue, check the Code Analyzer release notes for more info. Error and stacktrace: UnexpectedException: ApexStringValue{ value=Optional.empty} ApexValue(ApexStringValue) {status=INITIALIZED, declarationVertex=VariableDeclaration{properties={FirstChild=false, BeginLine=464, Type=String, DefiningType_CaseSafe=relatablecore, LastChild=true, DefiningType=RelatableCore, EndLine=464, Name_CaseSafe=namefield, childIdx=1, BeginColumn=16, Name=nameField}}, valueVertex=LiteralExpression{properties={FirstChild=true, BeginLine=464, DefiningType_CaseSafe=relatablecore, LastChild=false, DefiningType=RelatableCore, EndLine=464, childIdx=0, LiteralType=NULL, BeginColumn=28}}, resolvedValues={}, returnedFrom=null, invocableExpression=null, method=null}: com.salesforce.graph.ops.ApexValueUtil.getTypeValue(ApexValueUtil.java:376);com.salesforce.graph.ops.ApexValueUtil.convertApexValueToString(ApexValueUtil.java:305);com.salesforce.rules.fls.apex.operations.FlsValidationRepresentation.addField(FlsValidationRepresentation.java:122);com.salesforce.rules.fls.apex.operations.FlsValidationRepresentation.addField(FlsValidationRepresentation.java:114);com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.convert(SchemaBasedValidationAnalyzer.java:185);com.salesforce.rules.fls.apex.operations.SchemaBasedValidationAnalyzer.checkForValidation(SchemaBasedValidationAnalyzer.java:77)

Method code where the error occurs:

`
@AuraEnabled
public static List getSObjectRows(String recordId,
List columnObjs,
List sObjectTypes,
List targetRecordIds,
Boolean isChildRows,
Boolean allowInlineEditing,
String filteredsObject,
List columnFilters,
Integer sortColumnIndex,
String sortDirection,
Integer queryLimit,
Integer offset){

    List<Object> rows = new List<Object>();
    Set<Id> recordIds = new Set<Id>();
    Integer queryCount = 0;

    for (Object sObj : sObjectTypes){

        if (queryCount < 10){

            Map<String,Object> sObjectMap = (Map<String,Object>)JSON.deserializeUntyped(JSON.serialize(sObj));
            Boolean isInline = (Boolean)sObjectMap.get('inline') == false;
            
            if ((!isChildRows && !isInline) || isChildRows || !targetRecordIds.isEmpty()){
                String childObjectName = (String)sObjectMap.get('name');
            
                if (String.isBlank(filteredsObject) || childObjectName == filteredsObject){
    
                    String lookupField = (String)sObjectMap.get('field');
        
                    // only retrieve records if sObject is accessible to running user
                    if (RelatableUtilities.sObjectAccessible(childObjectName)){
                        
                        List<Object> columnMappings = (List<Object>)sObjectMap.get('_columns');
                        Map<String,Object> formatting = (Map<String,Object>)sObjectMap.get('formatting');
                        List<Object> conditions = (List<Object>)formatting.get('conditions');

                        String sortByField;
    
                        if (sortColumnIndex != null){
                            Map<String,Object> sortColumnObj = (Map<String,Object>)columnMappings[sortColumnIndex];
                            Map<String,Object> sortByFieldObj = (Map<String,Object>)sortColumnObj.get('field');
                            sortByField = (String)sortByFieldObj.get('name');
                        }
    
                        if (String.isBlank(sortByField)){
                            sortByField = 'Id';
                        }
        
                        Boolean recordEditable = (Boolean)sObjectMap.get('editable');
                        Boolean recordDeletable = (Boolean)sObjectMap.get('deletable'); 
                        List<String> queryFields = getQueryFields(childObjectName,columnMappings,conditions);
    
                        Set<String> queryFieldSet = new Set<String>();
                        queryFieldSet.addAll(queryFields);
    
                        List<String> queryFieldsUnique = new List<String>();
                        queryFieldsUnique.addAll(queryFieldSet);
        
                        // if at least one query field has been selected, query for records
                        if (!queryFields.isEmpty()){

                            Map<String,Object> params = new Map<String,Object>();
                            params.put('recordId',recordId);
                            params.put('recordIds',recordIds);
                            
                            String databaseQuery = 
                                ' SELECT ' + String.join(queryFieldsUnique,', ') + 
                                ' FROM ' + childObjectName; 

                            if (!targetRecordIds.isEmpty()){
                                params.put('targetRecordIds',targetRecordIds);
                                databaseQuery += 
                                    ' WHERE Id IN :targetRecordIds ' + 
                                    ' AND Id NOT IN :recordIds ';
                            } else {
                                
                                
                                List<String> filterStrings = new List<String>();

                                // get additional filters 
                                List<Object> filterObjs = (List<Object>)sObjectMap.get('filters');
                                List<sObjectFilter> sObjectFilters = getsObjectFilters(filterObjs);
                                for (Integer x = 0; x < sObjectFilters.size(); x++){
                                    String paramKey = 'sObjectFilter' + x;
                                    params.put(paramKey,sObjectFilters[x].value);
                                    String filterString = sObjectFilters[x].fieldName + ' ' + sObjectFilters[x].operator + ' :' + paramKey;
                                    filterStrings.add(filterString);
                                }

                                List<sObjectFilter> sObjectColumnFilters = getColumnFilters(columnMappings,columnFilters);
                                for (Integer x = 0; x < sObjectColumnFilters.size(); x++){
                                    String paramKey = 'columnFilter' + x;
                                    params.put(paramKey,sObjectColumnFilters[x].value);
                                    String filterString = sObjectColumnFilters[x].fieldName + ' ' + sObjectColumnFilters[x].operator + ' :' + paramKey;
                                    filterStrings.add(filterString);
                                }

                                String nullsPlacement = sortDirection == 'ASC' ? 'NULLS FIRST' : 'NULLS LAST';
            
                                if (queryLimit > 50){
                                    queryLimit = 50;
                                }

                                String filters = '';

                                if (!filterStrings.isEmpty()){
                                    filters = ' AND ' + String.join(filterStrings, ' AND ');
                                }

                                databaseQuery += 
                                    ' WHERE ' + lookupField + ' = :recordId ' + filters + ' AND Id NOT IN :recordIds ' +
                                    ' ORDER BY ' + sortByField + ' ' + sortDirection + ' ' + nullsPlacement + 
                                    ' LIMIT ' + queryLimit + 
                                    ' OFFSET ' + offset;  
                            }

                            List<sObject> queryRecords = Database.queryWithBinds(String.escapeSingleQuotes(databaseQuery), params, AccessLevel.USER_MODE);

                            queryCount += 1;

                            // check sharing setting for object
                            // get Ids of all records
                            String sharingSetting = (String)sObjectMap.get('sharing');

                            /*  
                                We'd love to be able to query directly in the above query, by using (SELECT ..., UserRecordAccess.HasEditAccess FROM Account)
                                But this "field" is unreliable on certain objects, for example for Tasks. It is also not supported for objects which are
                                child in a master detail relationship.
                            */
                            Map<Id,Boolean> recordSharingEdits = RelatableUtilities.getRecordShares(queryRecords,childObjectName,sharingSetting,recordEditable);
 
                            for (sObject record : queryRecords){

                                recordIds.add((Id)record.get('Id'));
                                recordEditable = recordSharingEdits.get(record.Id);
        
                                Map<String,Object> recordMap = new Map<String,Object>();
                                List<Object> recordCells = new List<Object>();
    
                                for (Integer y = 0; y < columnMappings.size(); y++){
        
                                    Map<String,Object> columnMap = (Map<String,Object>)columnMappings[y];
                                    Map<String,Object> fieldMap = (Map<String,Object>)columnMap.get('field');
                                    String dataType = (String)fieldMap.get('datatype');
                                    Boolean filterable = (Boolean)fieldMap.get('filterable');
                                    String columnName = (String)fieldMap.get('name');
                                    Object columnValue = getColumnValue(columnName, record);
                                    String lookupName = (String)columnMap.get('lookup');
                                    Object lookupValue = null;
    
                                    if (lookupName != null){
                                        lookupValue = getColumnValue(lookupName, record);
                                        if (lookupValue == null){
                                            lookupValue = columnValue;
                                        }
                                    }
        
                                    Map<String,Object> cellMap = new Map<String,Object>();
                                    cellMap.put('editable',(Boolean)columnMap.get('editable'));
                                    cellMap.put('column',columnObjs[y]);
                                    cellMap.put('value',columnValue);
                                    cellMap.put('lookup',lookupValue);
                                    cellMap.put('field',columnName);
                                    cellMap.put('datatype',dataType);
                                    cellMap.put('filterable',filterable);
                                    cellMap.put('editing',false);
                                    recordCells.add(cellMap);
                                }
        
                                recordMap.put('editable',recordEditable);
                                recordMap.put('deletable',recordDeletable);
                                recordMap.put('cells',recordCells);
                                recordMap.put('record',record);
                                recordMap.put('sObject',sObjectMap);
                                rows.add(recordMap);
                            }
                        }
                    }
                }
            }
        }
    }

    return rows;
}`

Steps To Reproduce:
I ran the following scanner:
sf scanner run dfa -f html -o QA/appexchange/CodeAnalyzerDFA.html -t './' -c 'Security' --projectdir='./'

Desktop:
Provide these details:

Operating System: Mac OS
Code Analyzer version: v3.20.0
Salesforce CLI version: @salesforce/cli/2.23.20 win32-x64 node-v18.19.0
Additional Context:

Workaround:
Tried the directives to exclude from the engine, but it doesn't work
Urgency:
Medium

@johnbelosf johnbelosf added the BUG P3 Rarely Malfunction label Feb 20, 2024
Copy link

git2gus bot commented Feb 20, 2024

This issue has been linked to a new work item: W-15080645

@stephen-carter-at-sf stephen-carter-at-sf added the SFGE Issues related to the Salesforce Graph Engine label May 23, 2024
@stephen-carter-at-sf stephen-carter-at-sf added the duplicate This issue or pull request already exists label Jun 3, 2024
@stephen-carter-at-sf
Copy link
Collaborator

Marking this as a duplicate of #1497

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BUG P3 Rarely Malfunction duplicate This issue or pull request already exists SFGE Issues related to the Salesforce Graph Engine
Projects
None yet
Development

No branches or pull requests

3 participants