/**
   * Looks up a column in the database. If the column and table are not found, they are created, and
   * added to the schema. This is prevent foreign key relationships from having a null pointer.
   */
  private MutableColumn lookupOrCreateColumn(
      final String catalogName,
      final String schemaName,
      final String tableName,
      final String columnName) {
    final boolean supportsCatalogs =
        getRetrieverConnection().getDatabaseSystemParameters().isSupportsCatalogs();
    MutableColumn column = null;
    final MutableSchema schema = lookupSchema(supportsCatalogs ? catalogName : null, schemaName);
    if (schema != null) {
      MutableTable table = schema.getTable(tableName);
      if (table != null) {
        column = table.getColumn(columnName);
      }

      if (column == null) {
        // Create the table, but do not add it to the schema
        table = new MutableTable(schema, tableName);
        column = new MutableColumn(table, columnName);
        table.addColumn(column);

        LOGGER.log(
            Level.FINER,
            String.format(
                "Creating new column that is referenced by a foreign key: %s",
                column.getFullName()));
      }
    }
    return column;
  }
  private void createPrivileges(final MetadataResultSet results, final boolean privilegesForColumn)
      throws SQLException {
    while (results.next()) {
      final String catalogName = quotedName(results.getString("TABLE_CAT"));
      final String schemaName = quotedName(results.getString("TABLE_SCHEM"));
      final String tableName = quotedName(results.getString("TABLE_NAME"));
      final String columnName;
      if (privilegesForColumn) {
        columnName = quotedName(results.getString("COLUMN_NAME"));
      } else {
        columnName = null;
      }

      final MutableTable table = lookupTable(catalogName, schemaName, tableName);
      if (table == null) {
        continue;
      }

      final MutableColumn column = table.getColumn(columnName);
      if (privilegesForColumn && column == null) {
        continue;
      }

      final String privilegeName = results.getString("PRIVILEGE");
      final String grantor = results.getString("GRANTOR");
      final String grantee = results.getString("GRANTEE");
      final boolean isGrantable = results.getBoolean("IS_GRANTABLE");

      final MutablePrivilege<?> privilege;
      if (privilegesForColumn) {
        final MutablePrivilege<Column> columnPrivilege = column.getPrivilege(privilegeName);
        if (columnPrivilege == null) {
          privilege = new MutablePrivilege<>(column, privilegeName);
          column.addPrivilege((MutablePrivilege<Column>) privilege);
        } else {
          privilege = columnPrivilege;
        }
      } else {
        final MutablePrivilege<Table> tablePrivilege = table.getPrivilege(privilegeName);
        if (tablePrivilege == null) {
          privilege = new MutablePrivilege<>(table, privilegeName);
          table.addPrivilege((MutablePrivilege<Table>) privilege);
        } else {
          privilege = tablePrivilege;
        }
      }
      privilege.addGrant(grantor, grantee, isGrantable);
      privilege.addAttributes(results.getAttributes());

      if (privilegesForColumn) {
        column.addPrivilege((MutablePrivilege<Column>) privilege);
      } else {
        table.addPrivilege((MutablePrivilege<Table>) privilege);
      }
    }
  }
  private void createIndices(final MutableTable table, final MetadataResultSet results)
      throws SQLException {
    try {
      while (results.next()) {
        // "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME"
        String indexName = quotedName(results.getString("INDEX_NAME"));
        if (Utility.isBlank(indexName)) {
          indexName = UNKNOWN;
        }
        LOGGER.log(
            Level.FINER, String.format("Retrieving index: %s.%s", table.getFullName(), indexName));
        final String columnName = quotedName(results.getString("COLUMN_NAME"));
        if (Utility.isBlank(columnName)) {
          continue;
        }

        MutableIndex index = table.getIndex(indexName);
        if (index == null) {
          index = new MutableIndex(table, indexName);
          table.addIndex(index);
        }

        final boolean uniqueIndex = !results.getBoolean("NON_UNIQUE");
        final int type = results.getInt("TYPE", IndexType.unknown.getId());
        final int ordinalPosition = results.getInt("ORDINAL_POSITION", 0);
        final IndexColumnSortSequence sortSequence =
            IndexColumnSortSequence.valueOfFromCode(results.getString("ASC_OR_DESC"));
        final int cardinality = results.getInt("CARDINALITY", 0);
        final int pages = results.getInt("PAGES", 0);

        final MutableColumn column = table.getColumn(columnName);
        if (column != null) {
          column.setPartOfUniqueIndex(uniqueIndex);
          final MutableIndexColumn indexColumn = new MutableIndexColumn(index, column);
          indexColumn.setIndexOrdinalPosition(ordinalPosition);
          indexColumn.setSortSequence(sortSequence);
          //
          index.addColumn(indexColumn);
          index.setUnique(uniqueIndex);
          index.setType(IndexType.valueOf(type));
          index.setCardinality(cardinality);
          index.setPages(pages);
          index.addAttributes(results.getAttributes());
        }
      }
    } finally {
      results.close();
    }
  }
 private MutableColumn lookupOrCreateColumn(
     final MutableTable table, final String columnName, final boolean add) {
   MutableColumn column = null;
   if (table != null) {
     column = table.getColumn(columnName);
   }
   if (column == null) {
     column = new MutableColumn(table, columnName);
     if (add) {
       LOGGER.log(Level.FINER, String.format("Adding column to table: %s", column.getFullName()));
       table.addColumn(column);
     }
   }
   return column;
 }
  /**
   * Retrieves additional column attributes from the database.
   *
   * @throws SQLException On a SQL exception
   */
  void retrieveAdditionalColumnAttributes() throws SQLException {
    final InformationSchemaViews informationSchemaViews =
        getRetrieverConnection().getInformationSchemaViews();
    if (!informationSchemaViews.hasAdditionalColumnAttributesSql()) {
      LOGGER.log(Level.FINE, "Additional column attributes SQL statement was not provided");
      return;
    }
    final String columnAttributesSql = informationSchemaViews.getAdditionalColumnAttributesSql();

    final Connection connection = getDatabaseConnection();
    try (final Statement statement = connection.createStatement();
        final MetadataResultSet results =
            new MetadataResultSet(statement.executeQuery(columnAttributesSql)); ) {

      while (results.next()) {
        final String catalogName = quotedName(results.getString("TABLE_CATALOG"));
        final String schemaName = quotedName(results.getString("TABLE_SCHEMA"));
        final String tableName = quotedName(results.getString("TABLE_NAME"));
        final String columnName = quotedName(results.getString("COLUMN_NAME"));
        LOGGER.log(Level.FINER, "Retrieving additional column attributes: " + columnName);

        final MutableTable table = lookupTable(catalogName, schemaName, tableName);
        if (table == null) {
          LOGGER.log(
              Level.FINE,
              String.format("Cannot find table, %s.%s.%s", catalogName, schemaName, tableName));
          continue;
        }

        final MutableColumn column = table.getColumn(columnName);
        if (column == null) {
          LOGGER.log(
              Level.FINE,
              String.format(
                  "Cannot find column, %s.%s.%s.%s",
                  catalogName, schemaName, tableName, columnName));
          continue;
        }

        column.addAttributes(results.getAttributes());
      }
    } catch (final Exception e) {
      LOGGER.log(Level.WARNING, "Could not retrieve additional column attributes", e);
    }
  }
  void retrievePrimaryKey(final MutableTable table) throws SQLException {
    MetadataResultSet results = null;
    try {
      results =
          new MetadataResultSet(
              getMetaData()
                  .getPrimaryKeys(
                      unquotedName(table.getSchema().getCatalogName()),
                      unquotedName(table.getSchema().getSchemaName()),
                      unquotedName(table.getName())));

      MutablePrimaryKey primaryKey;
      while (results.next()) {
        // "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME"
        final String columnName = quotedName(results.getString("COLUMN_NAME"));
        final String primaryKeyName = quotedName(results.getString("PK_NAME"));
        final int keySequence = Integer.parseInt(results.getString("KEY_SEQ"));

        primaryKey = table.getPrimaryKey();
        if (primaryKey == null) {
          primaryKey = new MutablePrimaryKey(table, primaryKeyName);
        }

        // Register primary key information
        final MutableColumn column = table.getColumn(columnName);
        if (column != null) {
          column.setPartOfPrimaryKey(true);
          final MutableIndexColumn indexColumn = new MutableIndexColumn(primaryKey, column);
          indexColumn.setSortSequence(IndexColumnSortSequence.ascending);
          indexColumn.setIndexOrdinalPosition(keySequence);
          //
          primaryKey.addColumn(indexColumn);
        }

        table.setPrimaryKey(primaryKey);
      }
    } catch (final SQLException e) {
      throw new SchemaCrawlerSQLException("Could not retrieve primary keys for table " + table, e);
    } finally {
      if (results != null) {
        results.close();
      }
    }
  }