please fix the bugs in the following code
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class test5 {

 public static void main(String... args) {
 String sql = "SELECT \* FROM users WHERE age > 30 AND gender IN ('male', 'female') OR name = 'gg' AND NOT age = 20";
 System.out.println(convert(sql));
 }

 // Map of SQL operators to MongoDB operators
 private static final Map OPERATOR\_MAP = new HashMap<>();

 static {
 OPERATOR\_MAP.put("=", "$eq");
 OPERATOR\_MAP.put("!=", "$ne");
 OPERATOR\_MAP.put(">", "$gt");
 OPERATOR\_MAP.put(">=", "$gte");
 OPERATOR\_MAP.put("<", "$lt");
 OPERATOR\_MAP.put("<=", "$lte");
 OPERATOR\_MAP.put("IN", "$in");
 OPERATOR\_MAP.put("NOT IN", "$nin");
 }

 // Regular expression pattern for extracting SQL WHERE clause
 private static final Pattern WHERE\_PATTERN = Pattern
 .compile("WHERE\\s+(\\w+)\\s\*(=|!=|>|>=|<|<=|IN|NOT IN)\\s\*(\\w+)");

 // Regular expression pattern for extracting SQL JOIN clause
 private static final Pattern JOIN\_PATTERN = Pattern.compile("JOIN\\s+(\\w+)\\s+ON\\s+(\\w+)\\s\*=\\s\*(\\w+)");

 // Regular expression pattern for extracting SQL COUNT clause
 private static final Pattern COUNT\_PATTERN = Pattern.compile("COUNT\\((\\w+)\\)");

 /\*\*
 \* Extracts a clause (e.g., SELECT, FROM, WHERE) from a SQL query.
 \*
 \* @param sql the SQL query
 \* @param clause the clause to extract
 \* @return the extracted clause, or null if the clause is not found
 \*/
 private static String extractClause(String sql, String clause) {
 // Find the index of the clause in the SQL query
 int index = sql.indexOf(clause);
 if (index == -1) {
 // If the clause is not found, return null
 return null;
 }

 // Extract the clause by finding the first semicolon after the clause
 index = sql.indexOf(";", index);
 if (index == -1) {
 // If no semicolon is found, return the rest of the query
 return sql.substring(clause.length());
 } else {
 // If a semicolon is found, return the clause up to the semicolon
 return sql.substring(clause.length(), index);
 }
 }

 /\*\*
 \* Converts a SQL WHERE clause to a MongoDB filter.
 \*
 \* @param whereClause the SQL WHERE clause to convert
 \* @return the MongoDB filter
 \*/
 public static String convertWhereClause(String whereClause) {
 // Extract the left hand side, operator, and right hand side of the WHERE clause
 Matcher whereMatcher = WHERE\_PATTERN.matcher(whereClause);
 if (whereMatcher.find()) {
 String lhs = whereMatcher.group(1);
 String op = whereMatcher.group(2);
 String rhs = whereMatcher.group(3);

 // Convert the SQL operator to a MongoDB operator
 op = OPERATOR\_MAP.get(op);

 // Return the MongoDB filter
 return String.format("%s: {%s: %s}", lhs, op, rhs);
 }
 return "";
 }

 public static String convertJoinClause(String joinClause) {
 // Extract the left and right collection and field names from the JOIN clause
 Matcher joinMatcher = JOIN\_PATTERN.matcher(joinClause);
 if (joinMatcher.find()) {
 String leftCollection = joinMatcher.group(1);
 String leftField = joinMatcher.group(2);
 String rightField = joinMatcher.group(3);

 // Return the MongoDB lookup stage
 return String.format(", {$lookup: {from: '%s', localField: '%s', foreignField: '%s', as: '%s'}}",
 leftCollection, leftField, rightField, leftCollection);
 }

 return "";
 }

 public static String convertHavingClause(String havingClause) {
 // Extract the left hand side, operator, and right hand side of the HAVING
 // clause
 Matcher havingMatcher = WHERE\_PATTERN.matcher(havingClause);
 if (havingMatcher.find()) {
 String lhs = havingMatcher.group(1);
 String op = havingMatcher.group(2);
 String rhs = havingMatcher.group(3);

 // Convert the SQL operator to a MongoDB operator
 op = OPERATOR\_MAP.get(op);

 // Return the MongoDB filter
 return String.format("%s: {%s: %s}", lhs, op, rhs);
 }

 return "";
 }

 /\*\*
 \* Converts a SQL query to a MongoDB query.
 \*
 \* @param sql the SQL query to convert
 \* @return the MongoDB query
 \*/
 public static String convert(String sql) {
 // Initialize the MongoDB query
 StringBuilder mongoDB = new StringBuilder();

 // Extract the SELECT clause
 String selectClause = extractClause(sql, "SELECT");
 if (selectClause != null) {
 // Check if the SELECT clause contains a COUNT function
 Matcher countMatcher = COUNT\_PATTERN.matcher(selectClause);
 if (countMatcher.find()) {
 // If the SELECT clause contains a COUNT function, add a MongoDB
 // count stage to the pipeline
 mongoDB.append("[{$count: ");
 mongoDB.append(countMatcher.group(1));
 mongoDB.append("}]");
 } else {
 // If the SELECT clause does not contain a COUNT function, add
 // a MongoDB projection stage to the pipeline
 mongoDB.append("[{$project: {");
 mongoDB.append(selectClause);
 mongoDB.append("}}]");
 }
 }

 // Extract the FROM clause
 String fromClause = extractClause(sql, "FROM");
 if (fromClause != null) {
 // Add a MongoDB match stage to the pipeline
 mongoDB.append(", {$match: {");

 // Extract the WHERE clause
 String whereClause = extractClause(sql, "WHERE");
 if (whereClause != null) {
 // Convert the SQL WHERE clause to a MongoDB filter
 mongoDB.append(convertWhereClause(whereClause));
 }

 // Extract the JOIN clause
 String joinClause = extractClause(sql, "JOIN");
 if (joinClause != null) {
 // Convert the SQL JOIN clause to a MongoDB lookup stage
 mongoDB.append(convertJoinClause(joinClause));
 }

 // Extract the GROUP BY clause
 String groupByClause = extractClause(sql, "GROUP BY");
 if (groupByClause != null) {
 // Add a MongoDB group stage to the pipeline
 mongoDB.append(", {$group: {\_id: ");
 mongoDB.append(groupByClause);
 mongoDB.append("}}");
 }

 // Extract the HAVING clause
 String havingClause = extractClause(sql, "HAVING");
 if (havingClause != null) {
 // Add a MongoDB match stage after the group stage to filter the grouped
 // documents
 mongoDB.append(", {$match: {");
 mongoDB.append(convertHavingClause(havingClause));
 mongoDB.append("}}");
 }

 // Close the pipeline
 mongoDB.append("]");
 }

 return mongoDB.toString();
 }

}
다음 코드에서 버그를 수정하세요.import java.util.HashMap;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;public class test5 { public static void main(String... args) { String sql = "SELECT \* FROM users WHERE age > 30 AND gender IN ('male', 'female') OR name = 'gg' AND NOT age = 20"; System.out.println(convert(sql)); } // SQL 연산자를 몽고DB 연산자로 매핑하기 private static final Map OPERATOR\_MAP = new HashMap<>(); static { OPERATOR\_MAP.put("=", "$eq"); OPERATOR\_MAP.put("!=", "$ne"); OPERATOR\_MAP.put(">", "$gt"); OPERATOR\_MAP.put(">=", "$gte"); OPERATOR\_MAP.put("<", "$lt"); OPERATOR\_MAP.put("<=", "$lte"); OPERATOR\_MAP.put("IN", "$in"); OPERATOR\_MAP.put("NOT IN", "$nin"); } // SQL WHERE 절을 추출하기 위한 정규식 패턴 비공개 정적 최종 패턴 WHERE\_PATTERN = 패턴 .compile("WHERE\\s+(\\w+)\\s\*(=|!=|>|>=|<|<=|IN|NOT IN)\\s\*(\\w+)"); // SQL JOIN 절을 추출하기 위한 정규식 패턴 private static final Pattern JOIN\_PATTERN = Pattern.compile("JOIN\\s+(\\w+)\\s+ON\\s+(\\w+)\\s\*=\\s\*(\\w+)"); // SQL COUNT 절을 추출하기 위한 정규식 패턴 private static final Pattern COUNT\_PATTERN = Pattern.compile("COUNT\\((\\w+)\\)"); /\*\* \* SQL 쿼리로부터 절 (예, SELECT, FROM, WHERE)을 추출합니다. \* \* @param sql SQL 쿼리 \* @param clause 추출할 절 \* 추출된 절을 반환하거나 절을 찾을 수 없는 경우 null을 반환합니다. \*/ private static String extractClause(String sql, String clause) { // SQL 쿼리에서 절의 인덱스를 찾습니다. int index = sql.indexOf(clause); if (index == -1) { // 절을 찾지 못하면 null을 반환합니다. null을 반환합니다; } // 절 뒤의 첫 번째 세미콜론을 찾아서 절을 추출합니다. index = sql.indexOf(";", index); if (index == -1) { // 세미콜론이 발견되지 않으면 나머지 쿼리를 반환합니다. return sql.substring(clause.length()); } else { // 세미콜론이 발견되면, 세미콜론까지 절을 반환합니다. return sql.substring(clause.length(), index); } } /\*\* \* SQL WHERE 절을 몽고DB 필터로 변환합니다. \* \* @param where변환할 SQL WHERE 절입니다. \* @return MongoDB 필터 \*/ public static String convertWhereClause(String whereClause) { // WHERE 절의 좌변, 연산자, 우변을 추출합니다. Matcher whereMatcher = WHERE\_PATTERN.matcher(whereClause); if (whereMatcher.find()) { String lhs = whereMatcher.group(1); String op = whereMatcher.group(2); String rhs = whereMatcher.group(3); // SQL 연산자를 몽고DB 연산자로 변환합니다. op = OPERATOR\_MAP.get(op); // MongoDB 필터를 반환합니다. 반환 String.format("%s: {%s: %s}", lhs, op, rhs); } 반환 ""; }   // JOIN 절에서 왼쪽 및 오른쪽 컬렉션과 필드 이름을 추출합니다. Matcher joinMatcher = JOIN\_PATTERN.matcher(joinClause); if (joinMatcher.find()) { String leftCollection = joinMatcher.group(1); String leftField = joinMatcher.group(2); String rightField = joinMatcher.group(3); // 몽고DB 조회 단계를 반환합니다. return String.format(", {$lookup: {from: '%s', localField: '%s', foreignField: '%s', as: '%s'}}", 왼쪽 컬렉션, 왼쪽 필드, 오른쪽 필드, 왼쪽 컬렉션); } 반환 ""; }   // HAVING의 왼쪽, 연산자, 오른쪽을 추출합니다. // 절을 추출합니다. Matcher havingMatcher = WHERE\_PATTERN.matcher(havingClause); if (havingMatcher.find()) { String lhs = havingMatcher.group(1); String op = havingMatcher.group(2); String rhs = havingMatcher.group(3); // SQL 연산자를 몽고DB 연산자로 변환합니다. op = OPERATOR\_MAP.get(op); // MongoDB 필터를 반환합니다. 반환 String.format("%s: {%s: %s}", lhs, op, rhs); } 반환 ""; } /\*\* \* SQL 쿼리를 몽고DB 쿼리로 변환합니다. \* \* @param sql 변환할 SQL 쿼리 \* @return MongoDB 쿼리를 반환합니다. \*/   // 몽고DB 쿼리를 초기화합니다. StringBuilder mongoDB = new StringBuilder(); // SELECT 절 추출 String selectClause = extractClause(sql, "SELECT"); if (selectClause != null) { // SELECT 절에 COUNT 함수가 포함되어 있는지 확인합니다. 일치자 countMatcher = COUNT\_PATTERN.matcher(selectClause); if (countMatcher.find()) {} // SELECT 절에 COUNT 함수가 포함된 경우, 파이프라인에 MongoDB // 카운트 단계를 파이프라인에 추가합니다. mongoDB.append("[{$count: "); mongoDB.append(countMatcher.group(1)); mongoDB.append("}]"); } else { // SELECT 절에 COUNT 함수가 포함되어 있지 않은 경우 // 파이프라인에 MongoDB 투영 단계를 추가합니다. mongoDB.append("[{$project: {"); mongoDB.append(selectClause); mongoDB.append("}}]"); } } // FROM 절 추출 String fromClause = extractClause(sql, "FROM"); if (fromClause != null) { // 파이프라인에 MongoDB 일치 단계를 추가합니다. mongoDB.append(", {$match: {"); // Ext