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