public DatalogProgram constructDatalogProgram() {
    DatalogProgram datalog = dfac.getDatalogProgram();
    LinkedList<String> errorMessage = new LinkedList<String>();
    for (OBDAMappingAxiom axiom : mappingList) {
      try {
        // Obtain the target and source query from each mapping axiom in
        // the model.
        CQIE targetQuery = (CQIE) axiom.getTargetQuery();

        // Get the parsed sql, since it is already parsed by the mapping
        // parser
        // consider also MetaMappingExpander
        // VisitedQuery queryParsed = ...;

        OBDASQLQuery sourceQuery = (OBDASQLQuery) axiom.getSourceQuery();

        // Construct the SQL query tree from the source query
        VisitedQuery queryParsed = translator.constructParser(sourceQuery.toString());

        // Create a lookup table for variable swapping
        LookupTable lookupTable = createLookupTable(queryParsed);

        // We can get easily the table from the SQL
        ArrayList<RelationJSQL> tableList = queryParsed.getTableSet();

        // Construct the body from the source query
        ArrayList<Function> atoms = new ArrayList<Function>();
        for (RelationJSQL table : tableList) {
          // Construct the URI from the table name
          String tableName = table.getGivenName();
          String predicateName = tableName;

          // Construct the predicate using the table name
          int arity = dbMetaData.getDefinition(tableName).countAttribute();
          Predicate predicate = dfac.getPredicate(predicateName, arity);

          // Swap the column name with a new variable from the lookup
          // table
          List<Term> terms = new ArrayList<Term>();
          for (int i = 1; i <= arity; i++) {
            String columnName =
                dbMetaData.getFullQualifiedAttributeName(tableName, table.getAlias(), i);
            String termName = lookupTable.lookup(columnName);
            if (termName == null) {
              throw new RuntimeException(
                  "Column '" + columnName + "'was not found in the lookup table: ");
            }
            Term term = dfac.getVariable(termName);
            terms.add(term);
          }
          // Create an atom for a particular table
          Function atom = dfac.getFunction(predicate, terms);
          atoms.add(atom);
        }

        // For the join conditions WE STILL NEED TO CONSIDER NOT EQUI
        // JOIN
        ArrayList<Expression> joinConditions = queryParsed.getJoinCondition();
        for (Expression predicate : joinConditions) {

          Function atom = getFunction(predicate, lookupTable);
          atoms.add(atom);
        }

        // For the selection "where" clause conditions
        SelectionJSQL selection = queryParsed.getSelection();
        if (selection != null) {

          // Stack for filter function
          Stack<Function> filterFunctionStack = new Stack<Function>();

          Expression conditions = selection.getRawConditions();
          Function filterFunction = getFunction(conditions, lookupTable);
          filterFunctionStack.push(filterFunction);

          // The filter function stack must have 1 element left
          if (filterFunctionStack.size() == 1) {
            Function filterFunct = filterFunctionStack.pop();
            Function atom =
                dfac.getFunction(filterFunct.getFunctionSymbol(), filterFunct.getTerms());
            atoms.add(atom);
          } else {
            throwInvalidFilterExpressionException(filterFunctionStack);
          }
        }

        // Construct the head from the target query.
        List<Function> atomList = targetQuery.getBody();
        // for (Function atom : atomList) {
        Iterator<Function> atomListIter = atomList.iterator();

        while (atomListIter.hasNext()) {
          Function atom = atomListIter.next();
          List<Term> terms = atom.getTerms();
          List<Term> newterms = new LinkedList<Term>();
          for (Term term : terms) {
            newterms.add(updateTerm(term, lookupTable));
          }
          Function newhead = dfac.getFunction(atom.getPredicate(), newterms);
          CQIE rule = dfac.getCQIE(newhead, atoms);
          datalog.appendRule(rule);
        }

      } catch (Exception e) {
        errorMessage.add(
            "Error in mapping with id: "
                + axiom.getId()
                + " \n Description: "
                + e.getMessage()
                + " \nMapping: ["
                + axiom.toString()
                + "]");
      }
    }

    if (errorMessage.size() > 0) {
      StringBuilder errors = new StringBuilder();
      for (String error : errorMessage) {
        errors.append(error + "\n");
      }
      final String msg =
          "There was an error analyzing the following mappings. Please correct the issue(s) to continue.\n"
              + errors.toString();
      RuntimeException r = new RuntimeException(msg);
      throw r;
    }
    return datalog;
  }
  private LookupTable createLookupTable(VisitedQuery queryParsed) throws JSQLParserException {
    LookupTable lookupTable = new LookupTable();

    // Collect all the possible column names from tables.
    ArrayList<RelationJSQL> tableList = queryParsed.getTableSet();

    // Collect all known column aliases
    HashMap<String, String> aliasMap = queryParsed.getAliasMap();

    int offset = 0; // the index offset

    for (RelationJSQL table : tableList) {

      String tableName = table.getTableName();
      String tableGivenName = table.getGivenName();
      DataDefinition def = dbMetaData.getDefinition(tableGivenName);
      if (def == null) {
        def = dbMetaData.getDefinition(tableName);
        if (def == null) {
          throw new RuntimeException("Definition not found for table '" + tableGivenName + "'.");
        }
      }
      int size = def.countAttribute();

      for (int i = 1; i <= size; i++) {
        // assigned index number
        int index = i + offset;

        // simple attribute name
        String columnName = dbMetaData.getAttributeName(tableGivenName, i);

        lookupTable.add(columnName, index);

        String lowercaseColumn = columnName.toLowerCase();

        if (aliasMap.containsKey(lowercaseColumn)) { // register the alias name, if any
          lookupTable.add(aliasMap.get(lowercaseColumn), columnName);
        }

        // attribute name with table name prefix
        String tableColumnName = tableName + "." + columnName;
        lookupTable.add(tableColumnName, index);

        // attribute name with table name prefix
        String tablecolumnname = tableColumnName.toLowerCase();
        if (aliasMap.containsKey(tablecolumnname)) { // register the alias name, if any
          lookupTable.add(aliasMap.get(tablecolumnname), tableColumnName);
        }

        // attribute name with table given name prefix
        String givenTableColumnName = tableGivenName + "." + columnName;
        lookupTable.add(givenTableColumnName, tableColumnName);

        String giventablecolumnname = givenTableColumnName.toLowerCase();
        if (aliasMap.containsKey(giventablecolumnname)) { // register the alias name, if any
          lookupTable.add(aliasMap.get(giventablecolumnname), tableColumnName);
        }

        // full qualified attribute name
        String qualifiedColumnName = dbMetaData.getFullQualifiedAttributeName(tableGivenName, i);
        lookupTable.add(qualifiedColumnName, tableColumnName);
        String qualifiedcolumnname = qualifiedColumnName.toLowerCase();
        if (aliasMap.containsKey(qualifiedcolumnname)) { // register the alias name, if any
          lookupTable.add(aliasMap.get(qualifiedcolumnname), tableColumnName);
        }

        // full qualified attribute name using table alias
        String tableAlias = table.getAlias();
        if (tableAlias != null) {
          String qualifiedColumnAlias =
              dbMetaData.getFullQualifiedAttributeName(tableGivenName, tableAlias, i);
          lookupTable.add(qualifiedColumnAlias, index);
          String aliasColumnName = tableAlias.toLowerCase() + "." + lowercaseColumn;
          if (aliasMap.containsKey(aliasColumnName)) { // register the alias name, if any
            lookupTable.add(aliasMap.get(aliasColumnName), qualifiedColumnAlias);
          }
        }

        // check if we do not have subselect with alias name assigned
        for (SelectJSQL subSelect : queryParsed.getSubSelectSet()) {
          String subSelectAlias = subSelect.getAlias();
          if (subSelectAlias != null) {
            String aliasColumnName = subSelectAlias.toLowerCase() + "." + lowercaseColumn;
            lookupTable.add(aliasColumnName, index);
            if (aliasMap.containsKey(aliasColumnName)) { // register the alias name, if any
              lookupTable.add(aliasMap.get(aliasColumnName), aliasColumnName);
            }
          }
        }
      }
      offset += size;
    }
    return lookupTable;
  }