001package gudusoft.gsqlparser.resolver2.scope; 002 003import gudusoft.gsqlparser.resolver2.ScopeType; 004import gudusoft.gsqlparser.resolver2.matcher.INameMatcher; 005import gudusoft.gsqlparser.resolver2.model.ScopeChild; 006import gudusoft.gsqlparser.resolver2.namespace.INamespace; 007import gudusoft.gsqlparser.resolver2.namespace.OraclePackageNamespace; 008import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage; 009 010import java.util.*; 011 012/** 013 * Scope for Oracle PL/SQL package bodies. 014 * 015 * <p>Provides access to package-level declarations for all nested 016 * procedures, functions, and blocks within the package body. 017 * 018 * <p>Name resolution priority within package body: 019 * <ol> 020 * <li>Local variables (PlsqlBlockScope)</li> 021 * <li>Package members (OraclePackageNamespace)</li> 022 * <li>SQL table columns (SelectScope/FromScope)</li> 023 * <li>External packages (via GlobalScope)</li> 024 * </ol> 025 */ 026public class OraclePackageScope extends AbstractScope { 027 028 /** Package namespace containing package-level declarations */ 029 private final OraclePackageNamespace packageNamespace; 030 031 /** Package name for qualified reference resolution */ 032 private final String packageName; 033 034 /** Child scopes */ 035 private final List<ScopeChild> children = new ArrayList<>(); 036 037 /** Child ordinal counter */ 038 private int childOrdinal = 0; 039 040 /** 041 * Create a new Oracle package scope. 042 * 043 * @param parent The parent scope 044 * @param packageStmt The package AST node 045 * @param packageNamespace The namespace containing package members 046 */ 047 public OraclePackageScope(IScope parent, TPlsqlCreatePackage packageStmt, 048 OraclePackageNamespace packageNamespace) { 049 super(parent, packageStmt, ScopeType.PLSQL_BLOCK); // Reuse PLSQL_BLOCK type 050 this.packageNamespace = packageNamespace; 051 this.packageName = packageNamespace != null ? packageNamespace.getPackageName() : null; 052 } 053 054 /** 055 * Get the package namespace. 056 * 057 * @return The OraclePackageNamespace containing package-level declarations 058 */ 059 public OraclePackageNamespace getPackageNamespace() { 060 return packageNamespace; 061 } 062 063 /** 064 * Get the package name. 065 * 066 * @return The package name 067 */ 068 public String getPackageName() { 069 return packageName; 070 } 071 072 @Override 073 public void addChild(INamespace namespace, String alias, boolean nullable) { 074 children.add(new ScopeChild(childOrdinal++, alias, namespace, nullable)); 075 } 076 077 @Override 078 public List<ScopeChild> getChildren() { 079 return children; 080 } 081 082 @Override 083 public INamespace resolveTable(String tableName) { 084 // Check if this is a reference to our package 085 if (packageName != null && packageName.equalsIgnoreCase(tableName)) { 086 return packageNamespace; 087 } 088 // Delegate to parent for other table/package lookups 089 return parent.resolveTable(tableName); 090 } 091 092 @Override 093 public void resolve(List<String> names, INameMatcher matcher, 094 boolean deep, IResolved resolved) { 095 // Handle unqualified references - check if it's a package member 096 if (names.size() == 1 && packageNamespace != null) { 097 String name = names.get(0); 098 if (packageNamespace.hasMember(name)) { 099 resolved.found(packageNamespace, false, this, null, names); 100 return; 101 } 102 } 103 104 // Handle qualified references like pkg.member 105 if (names.size() >= 2 && packageNamespace != null) { 106 String firstName = names.get(0); 107 if (matcher.matches(firstName, packageName)) { 108 String memberName = names.get(1); 109 if (packageNamespace.hasMember(memberName)) { 110 resolved.found(packageNamespace, false, this, null, 111 Collections.singletonList(memberName)); 112 return; 113 } 114 } 115 } 116 117 // Delegate to parent (GlobalScope or outer scope) 118 parent.resolve(names, matcher, deep, resolved); 119 } 120 121 @Override 122 public List<INamespace> getVisibleNamespaces() { 123 List<INamespace> namespaces = new ArrayList<>(); 124 if (packageNamespace != null) { 125 namespaces.add(packageNamespace); 126 } 127 namespaces.addAll(parent.getVisibleNamespaces()); 128 return namespaces; 129 } 130 131 @Override 132 public String toString() { 133 return "OraclePackageScope(" + packageName + 134 ", members=" + (packageNamespace != null ? packageNamespace.getMembers().size() : 0) + ")"; 135 } 136}