// Path: octopus-core/src/main/java/kr/co/bitnine/octopus/sql/OctopusSqlObjectPrivileges.java
// static class OctopusSqlGrantObjPrivs extends OctopusSqlObjectPrivileges {
//     OctopusSqlGrantObjPrivs(List<ObjectPrivilege> objPrivs, String[] objName, List<String> grantees) {
//         super(objPrivs, objName, grantees);
//     }
// 
//     @Override
//     public Type getType() {
//         return Type.GRANT_OBJ_PRIVS;
//     }
// }
// 
// Path: octopus-core/src/main/java/kr/co/bitnine/octopus/sql/OctopusSqlObjectPrivileges.java
// static class OctopusSqlRevokeObjPrivs extends OctopusSqlObjectPrivileges {
//     OctopusSqlRevokeObjPrivs(List<ObjectPrivilege> objPrivs, String[] objName, List<String> revokees) {
//         super(objPrivs, objName, revokees);
//     }
// 
//     @Override
//     public Type getType() {
//         return Type.REVOKE_OBJ_PRIVS;
//     }
// }


import static kr.co.bitnine.octopus.sql.OctopusSqlSystemPrivileges.OctopusSqlGrantSysPrivs;
import static kr.co.bitnine.octopus.sql.OctopusSqlSystemPrivileges.OctopusSqlRevokeSysPrivs;
import kr.co.bitnine.octopus.meta.privilege.ObjectPrivilege;
import kr.co.bitnine.octopus.meta.privilege.SystemPrivilege;
import kr.co.bitnine.octopus.postgres.executor.TupleSet;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static kr.co.bitnine.octopus.sql.OctopusSqlObjectPrivileges.OctopusSqlGrantObjPrivs;
import static kr.co.bitnine.octopus.sql.OctopusSqlObjectPrivileges.OctopusSqlRevokeObjPrivs;
        }

        @Override
        public void exitCommentUser(OctopusSqlParser.CommentUserContext ctx) {
            assert commentTarget == null;

            commentTarget = new OctopusSqlObjectTarget();
            commentTarget.setType(OctopusSqlObjectTarget.Type.USER);
            commentTarget.setUser(ctx.user().getText());
        }

        @Override
        public void exitSetDataCategoryOn(OctopusSqlParser.SetDataCategoryOnContext ctx) {
            OctopusSqlObjectTarget target = new OctopusSqlObjectTarget();
            target.setType(OctopusSqlObjectTarget.Type.COLUMN);
            target.setDataSource(ctx.dataSourceName().getText());
            target.setSchema(ctx.schemaName().getText());
            target.setTable(ctx.tableName().getText());
            target.setColumn(ctx.columnName().getText());

            String category = ctx.category().getText();

            commands.add(new OctopusSqlSetDataCategoryOn(target, category));
        }

        List<OctopusSqlCommand> getSqlCommands() {
            return commands;
        }
    }

// Path: octopus-core/src/main/java/kr/co/bitnine/octopus/sql/OctopusSqlObjectPrivileges.java
// static class OctopusSqlGrantObjPrivs extends OctopusSqlObjectPrivileges {
//     OctopusSqlGrantObjPrivs(List<ObjectPrivilege> objPrivs, String[] objName, List<String> grantees) {
//         super(objPrivs, objName, grantees);
//     }
// 
//     @Override
//     public Type getType() {
//         return Type.GRANT_OBJ_PRIVS;
//     }
// }
// 
// Path: octopus-core/src/main/java/kr/co/bitnine/octopus/sql/OctopusSqlObjectPrivileges.java
// static class OctopusSqlRevokeObjPrivs extends OctopusSqlObjectPrivileges {
//     OctopusSqlRevokeObjPrivs(List<ObjectPrivilege> objPrivs, String[] objName, List<String> revokees) {
//         super(objPrivs, objName, revokees);
//     }
// 
//     @Override
//     public Type getType() {
//         return Type.REVOKE_OBJ_PRIVS;
//     }
// }


// Path: octopus-core/src/main/java/kr/co/bitnine/octopus/sql/OctopusSql.java
import static kr.co.bitnine.octopus.sql.OctopusSqlSystemPrivileges.OctopusSqlGrantSysPrivs;
import static kr.co.bitnine.octopus.sql.OctopusSqlSystemPrivileges.OctopusSqlRevokeSysPrivs;
import kr.co.bitnine.octopus.meta.privilege.ObjectPrivilege;
import kr.co.bitnine.octopus.meta.privilege.SystemPrivilege;
import kr.co.bitnine.octopus.postgres.executor.TupleSet;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static kr.co.bitnine.octopus.sql.OctopusSqlObjectPrivileges.OctopusSqlGrantObjPrivs;
import static kr.co.bitnine.octopus.sql.OctopusSqlObjectPrivileges.OctopusSqlRevokeObjPrivs;

        }

        @Override
        public void exitCommentUser(OctopusSqlParser.CommentUserContext ctx) {
            assert commentTarget == null;

            commentTarget = new OctopusSqlObjectTarget();
            commentTarget.setType(OctopusSqlObjectTarget.Type.USER);
            commentTarget.setUser(ctx.user().getText());
        }

        @Override
        public void exitSetDataCategoryOn(OctopusSqlParser.SetDataCategoryOnContext ctx) {
            OctopusSqlObjectTarget target = new OctopusSqlObjectTarget();
            target.setType(OctopusSqlObjectTarget.Type.COLUMN);
            target.setDataSource(ctx.dataSourceName().getText());
            target.setSchema(ctx.schemaName().getText());
            target.setTable(ctx.tableName().getText());
            target.setColumn(ctx.columnName().getText());

            String category = ctx.category().getText();

            commands.add(new OctopusSqlSetDataCategoryOn(target, category));
        }

        List<OctopusSqlCommand> getSqlCommands() {
            return commands;
        }
    }

    public static List<OctopusSqlCommand> parse(String query) {