Skip to content

Latest commit

 

History

History
297 lines (234 loc) · 20.6 KB

File metadata and controls

297 lines (234 loc) · 20.6 KB

PG AST Loc Field Coverage Scenarios

Goal: Add Loc field to all 139 AST node structs in pg/ast that are currently missing it, and set location tracking in the parser Verification: Parse SQL → navigate to node → verify sql[node.Loc.Start:node.Loc.End] matches expected source text Reference sources: pg/ast/parsenodes.go (struct definitions), pg/parser/*.go (node creation sites), existing Loc patterns (Alias, RangeVar, SelectStmt) Proof: go test ./pg/parser/... ./pg/parsertest/... | same | go test ./pg/...

Status: [ ] pending, [x] passing, [~] partial (needs upstream change)


Phase 1: Core Query Nodes

1.1 FROM Clause & Join Nodes (select.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/select.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go (shared with all sections) Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • JoinExpr — SELECT * FROM t1 JOIN t2 ON t1.id = t2.id → Loc covers t1 JOIN t2 ON t1.id = t2.id
  • JoinExpr LEFT — SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id → Loc covers full join expr
  • JoinExpr CROSS — SELECT * FROM t1 CROSS JOIN t2 → Loc covers cross join expr
  • JoinExpr NATURAL — SELECT * FROM t1 NATURAL JOIN t2 → Loc covers natural join expr
  • RangeSubselect — SELECT * FROM (SELECT 1) AS sub → Loc covers (SELECT 1) AS sub
  • RangeSubselect LATERAL — SELECT * FROM t1, LATERAL (SELECT * FROM t2) AS sub → Loc covers lateral subselect
  • RangeFunction — SELECT * FROM generate_series(1, 10) → Loc covers function call in FROM
  • RangeFunction WITH ORDINALITY — SELECT * FROM generate_series(1, 10) WITH ORDINALITY → Loc includes WITH ORDINALITY
  • RangeFunction ROWS FROM — SELECT * FROM ROWS FROM(generate_series(1,3), generate_series(1,4)) → Loc covers ROWS FROM
  • CurrentOfExpr — DELETE FROM t1 WHERE CURRENT OF cursor1 → Loc covers CURRENT OF cursor1
  • LockingClause — SELECT * FROM t1 FOR UPDATE → Loc covers FOR UPDATE
  • IntoClause — SELECT * INTO newtable FROM t1 → Loc covers INTO newtable

1.2 Expression Helper Nodes (expr.go, name.go, update.go, insert.go, create_table.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/expr.go, pg/parser/name.go, pg/parser/select.go, pg/parser/copy.go, pg/parser/maintenance.go, pg/parser/create_view.go, pg/parser/update.go, pg/parser/insert.go, pg/parser/create_table.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc Note: A_Star is currently struct{} (empty). Adding Loc changes its memory layout — verify all creation sites still compile.

  • A_Indices single — SELECT a[1] FROM t → Loc covers [1]
  • A_Indices slice — SELECT a[1:3] FROM t → Loc covers [1:3]
  • A_Indirection — SELECT (row).field FROM t → Loc covers .field indirection
  • A_Star — SELECT * FROM t → Loc covers * (created in expr.go, name.go, select.go, copy.go, maintenance.go, create_view.go)
  • MergeWhenClause MATCHED — MERGE INTO t USING s ON t.id=s.id WHEN MATCHED THEN UPDATE SET x=1 → Loc covers WHEN MATCHED THEN UPDATE SET x=1
  • MergeWhenClause NOT MATCHED — MERGE INTO t USING s ON t.id=s.id WHEN NOT MATCHED THEN INSERT VALUES(1) → Loc covers WHEN NOT MATCHED clause
  • MultiAssignRef — INSERT INTO t(a,b) SELECT 1,2 with multi-assign → Loc covers ref
  • TableLikeClause — CREATE TABLE t2 (LIKE t1 INCLUDING ALL) → Loc covers LIKE t1 INCLUDING ALL

1.3 JSON Nodes (json.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/json.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • JsonArgument — SELECT json_object('key': 'value') → Loc covers argument
  • JsonKeyValue — SELECT JSON_OBJECT('key' VALUE 'val') → Loc covers key-value pair
  • JsonObjectAgg — SELECT JSON_OBJECTAGG(k VALUE v) FROM t → Loc covers aggregate
  • JsonArrayAgg — SELECT JSON_ARRAYAGG(v) FROM t → Loc covers aggregate
  • JsonOutput — SELECT JSON_OBJECT('k': 'v' RETURNING text) → Loc covers RETURNING clause
  • JsonValueExpr — JSON value expression in JSON functions → Loc covers value expr

Phase 2: DDL Definition Nodes

2.1 Type & Operator Definitions (define.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/define.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • DefineStmt TYPE — CREATE TYPE mytype AS (a int, b text) → Loc covers full statement
  • DefineStmt OPERATOR — CREATE OPERATOR === (LEFTARG=int, RIGHTARG=int, FUNCTION=int4eq) → Loc covers full statement
  • DefineStmt AGGREGATE — CREATE AGGREGATE myagg(int) (SFUNC=int4pl, STYPE=int) → Loc covers full statement
  • CompositeTypeStmt — CREATE TYPE comptype AS (x int, y int) → Loc covers full statement
  • CreateEnumStmt — CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy') → Loc covers full statement
  • CreateRangeStmt — CREATE TYPE floatrange AS RANGE (SUBTYPE = float8) → Loc covers full statement
  • CreateOpClassStmt — CREATE OPERATOR CLASS myclass FOR TYPE int USING btree AS OPERATOR 1 < → Loc covers full statement
  • CreateOpFamilyStmt — CREATE OPERATOR FAMILY myfam USING btree → Loc covers full statement
  • CreateOpClassItem — individual item in operator class definition → Loc covers item
  • CreateConversionStmt — CREATE CONVERSION myconv FOR 'UTF8' TO 'LATIN1' FROM utf8_to_iso8859_1 → Loc covers full statement
  • CreateStatsStmt — CREATE STATISTICS mystats (dependencies) ON a, b FROM t → Loc covers full statement
  • AlterDefaultPrivilegesStmt — ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES TO public → Loc covers full statement
  • AlterOpFamilyStmt — ALTER OPERATOR FAMILY myfam USING btree ADD OPERATOR 1 <(int,int) → Loc covers full statement
  • AlterOperatorStmt — ALTER OPERATOR ===(int,int) SET (RESTRICT=eqsel) → Loc covers full statement
  • AlterStatsStmt — ALTER STATISTICS mystats SET STATISTICS 100 → Loc covers full statement
  • StatsElem — individual element in CREATE STATISTICS → Loc covers element

2.2 Extension Nodes (extension.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/extension.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreateExtensionStmt — CREATE EXTENSION hstore → Loc covers full statement
  • CreateAmStmt — CREATE ACCESS METHOD myam TYPE INDEX HANDLER myhandler → Loc covers full statement
  • CreateCastStmt — CREATE CAST (int AS text) WITH FUNCTION int4_to_text(int) → Loc covers full statement
  • CreateTransformStmt — CREATE TRANSFORM FOR int LANGUAGE plpgsql (FROM SQL WITH FUNCTION ..., TO SQL WITH FUNCTION ...) → Loc covers full statement
  • AlterExtensionStmt — ALTER EXTENSION hstore UPDATE TO '2.0' → Loc covers full statement
  • AlterExtensionContentsStmt — ALTER EXTENSION hstore ADD TABLE mytable → Loc covers full statement

2.3 Foreign Data Wrapper Nodes (fdw.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/fdw.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreateFdwStmt — CREATE FOREIGN DATA WRAPPER myfdw → Loc covers full statement
  • CreateForeignServerStmt — CREATE SERVER myserver FOREIGN DATA WRAPPER myfdw → Loc covers full statement
  • CreateForeignTableStmt — CREATE FOREIGN TABLE ft (a int) SERVER myserver → Loc covers full statement
  • CreatePLangStmt — CREATE LANGUAGE plmylang → Loc covers full statement
  • CreateUserMappingStmt — CREATE USER MAPPING FOR current_user SERVER myserver → Loc covers full statement
  • AlterFdwStmt — ALTER FOREIGN DATA WRAPPER myfdw OPTIONS (ADD host 'foo') → Loc covers full statement
  • AlterForeignServerStmt — ALTER SERVER myserver OPTIONS (SET host 'bar') → Loc covers full statement
  • AlterUserMappingStmt — ALTER USER MAPPING FOR current_user SERVER myserver OPTIONS (SET password 'x') → Loc covers full statement
  • DropUserMappingStmt — DROP USER MAPPING FOR current_user SERVER myserver → Loc covers full statement
  • ImportForeignSchemaStmt — IMPORT FOREIGN SCHEMA public FROM SERVER myserver INTO local_schema → Loc covers full statement

Phase 3: ALTER & Access Control Nodes

3.1 General ALTER Nodes (alter_misc.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/alter_misc.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • AlterCollationStmt — ALTER COLLATION "C" REFRESH VERSION → Loc covers full statement
  • AlterDomainStmt — ALTER DOMAIN mydom SET NOT NULL → Loc covers full statement
  • AlterEnumStmt — ALTER TYPE mood ADD VALUE 'great' → Loc covers full statement
  • AlterEventTrigStmt — ALTER EVENT TRIGGER mytrig DISABLE → Loc covers full statement
  • AlterFunctionStmt — ALTER FUNCTION myfunc(int) STABLE → Loc covers full statement
  • AlterObjectDependsStmt — ALTER FUNCTION myfunc DEPENDS ON EXTENSION hstore → Loc covers full statement
  • AlterObjectSchemaStmt — ALTER TABLE t SET SCHEMA newschema → Loc covers full statement
  • AlterOwnerStmt — ALTER TABLE t OWNER TO newowner → Loc covers full statement
  • AlterTableSpaceOptionsStmt — ALTER TABLESPACE myts SET (seq_page_cost=2) → Loc covers full statement
  • AlterTSConfigurationStmt — ALTER TEXT SEARCH CONFIGURATION myconfig ADD MAPPING FOR word WITH simple → Loc covers full statement
  • AlterTSDictionaryStmt — ALTER TEXT SEARCH DICTIONARY mydict (STOPWORDS = 'english') → Loc covers full statement
  • AlterTypeStmt — ALTER TYPE comptype ADD ATTRIBUTE c int → Loc covers full statement

3.2 ALTER TABLE Nodes (alter_table.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/alter_table.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • AlterTableStmt — ALTER TABLE t ADD COLUMN x int → Loc covers full statement
  • AlterTableCmd — individual ALTER TABLE sub-command → Loc covers the sub-command
  • AlterSeqStmt — ALTER SEQUENCE myseq RESTART WITH 1 → Loc covers full statement
  • AlterTableMoveAllStmt — ALTER TABLE ALL IN TABLESPACE ts1 SET TABLESPACE ts2 → Loc covers full statement
  • PartitionCmd — ALTER TABLE t ATTACH PARTITION p FOR VALUES FROM (1) TO (10) → Loc covers partition command
  • RenameStmt — ALTER TABLE t RENAME COLUMN old TO new → Loc covers full statement

3.3 Grant & Role Nodes (grant.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/grant.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • GrantStmt — GRANT SELECT ON t TO myrole → Loc covers full statement
  • GrantRoleStmt — GRANT myrole TO otheruser → Loc covers full statement
  • CreateRoleStmt — CREATE ROLE myrole WITH LOGIN → Loc covers full statement
  • AlterRoleStmt — ALTER ROLE myrole WITH SUPERUSER → Loc covers full statement
  • AlterRoleSetStmt — ALTER ROLE myrole SET search_path TO public → Loc covers full statement
  • AlterPolicyStmt — ALTER POLICY mypol ON t USING (true) → Loc covers full statement
  • CreatePolicyStmt — CREATE POLICY mypol ON t USING (true) → Loc covers full statement
  • DropRoleStmt — DROP ROLE myrole → Loc covers full statement
  • AccessPriv — individual privilege in GRANT → Loc covers privilege entry

3.4 Publication & Subscription Nodes (publication.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/publication.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreatePublicationStmt — CREATE PUBLICATION mypub FOR ALL TABLES → Loc covers full statement
  • AlterPublicationStmt — ALTER PUBLICATION mypub ADD TABLE t → Loc covers full statement
  • CreateSubscriptionStmt — CREATE SUBSCRIPTION mysub CONNECTION 'conninfo' PUBLICATION mypub → Loc covers full statement
  • AlterSubscriptionStmt — ALTER SUBSCRIPTION mysub SET PUBLICATION mypub → Loc covers full statement
  • PublicationTable — individual table in publication → Loc covers table reference
  • RuleStmt — CREATE RULE myrule AS ON INSERT TO t DO INSTEAD NOTHING → Loc covers full statement

Phase 4: Remaining Statement Nodes

4.1 Database & Schema Nodes (database.go, schema.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/database.go, pg/parser/schema.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreatedbStmt — CREATE DATABASE mydb → Loc covers full statement
  • AlterDatabaseStmt — ALTER DATABASE mydb SET TABLESPACE newtbs → Loc covers full statement
  • AlterDatabaseSetStmt — ALTER DATABASE mydb SET timezone TO 'UTC' → Loc covers full statement
  • DropdbStmt — DROP DATABASE mydb → Loc covers full statement
  • CreateSchemaStmt — CREATE SCHEMA myschema → Loc covers full statement
  • CreateTableSpaceStmt — CREATE TABLESPACE mytbs LOCATION '/data' → Loc covers full statement
  • CommentStmt — COMMENT ON TABLE t IS 'my comment' → Loc covers full statement
  • SecLabelStmt — SECURITY LABEL ON TABLE t IS 'classified' → Loc covers full statement
  • ObjectWithArgs — object reference with argument types (e.g., in DROP FUNCTION) → Loc covers object+args

4.2 Sequence, Function & Domain Nodes (sequence.go, create_function.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/sequence.go, pg/parser/create_function.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreateSeqStmt — CREATE SEQUENCE myseq START 1 → Loc covers full statement
  • CreateDomainStmt — CREATE DOMAIN posint AS int CHECK (VALUE > 0) → Loc covers full statement
  • CreateFunctionStmt — CREATE FUNCTION myfunc(int) RETURNS int AS $$ SELECT $1 $$ LANGUAGE sql → Loc covers full statement
  • FunctionParameter — individual parameter in function definition → Loc covers parameter
  • ReturnStmt — RETURN expr in function body → Loc covers RETURN statement

4.3 Trigger, Index & View Nodes (trigger.go, create_index.go, create_view.go, create_table.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/trigger.go, pg/parser/create_index.go, pg/parser/create_view.go, pg/parser/create_table.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • CreateTrigStmt — CREATE TRIGGER mytrig BEFORE INSERT ON t EXECUTE FUNCTION myfunc() → Loc covers full statement
  • CreateEventTrigStmt — CREATE EVENT TRIGGER myevt ON ddl_command_start EXECUTE FUNCTION myfunc() → Loc covers full statement
  • TriggerTransition — REFERENCING NEW TABLE AS newtab → Loc covers transition clause
  • IndexStmt — CREATE INDEX myidx ON t (col) → Loc covers full statement
  • IndexElem — individual index element → Loc covers element
  • ViewStmt — CREATE VIEW myview AS SELECT * FROM t → Loc covers full statement
  • CreateTableAsStmt — CREATE TABLE t AS SELECT 1 → Loc covers full statement
  • RefreshMatViewStmt — REFRESH MATERIALIZED VIEW myview → Loc covers full statement
  • CreateStmt — CREATE TABLE t (a int, b text) → Loc covers full statement

4.4 Utility Statement Nodes (utility.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/utility.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • ExplainStmt — EXPLAIN SELECT 1 → Loc covers full statement
  • CallStmt — CALL myproc() → Loc covers full statement
  • DoStmt — DO $$ BEGIN RAISE NOTICE 'hi'; END $$ → Loc covers full statement
  • CheckPointStmt — CHECKPOINT → Loc covers full statement
  • DiscardStmt — DISCARD ALL → Loc covers full statement
  • ListenStmt — LISTEN mychannel → Loc covers full statement
  • NotifyStmt — NOTIFY mychannel, 'payload' → Loc covers full statement
  • UnlistenStmt — UNLISTEN mychannel → Loc covers full statement
  • LoadStmt — LOAD 'mylib' → Loc covers full statement
  • ReassignOwnedStmt — REASSIGN OWNED BY oldrole TO newrole → Loc covers full statement

4.5 Cursor, Prepare & IO Nodes (cursor.go, prepare.go, copy.go, lock.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/cursor.go, pg/parser/prepare.go, pg/parser/copy.go, pg/parser/lock.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • DeclareCursorStmt — DECLARE mycur CURSOR FOR SELECT 1 → Loc covers full statement
  • FetchStmt — FETCH NEXT FROM mycur → Loc covers full statement
  • ClosePortalStmt — CLOSE mycur → Loc covers full statement
  • PrepareStmt — PREPARE myplan AS SELECT 1 → Loc covers full statement
  • ExecuteStmt — EXECUTE myplan → Loc covers full statement
  • CopyStmt — COPY t FROM STDIN → Loc covers full statement
  • LockStmt — LOCK TABLE t IN ACCESS EXCLUSIVE MODE → Loc covers full statement

4.6 Maintenance & SET Nodes (maintenance.go, set.go, drop.go)

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, pg/parser/maintenance.go, pg/parser/set.go, pg/parser/drop.go, pg/parsertest/loc_test.go Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • VacuumStmt — VACUUM t → Loc covers full statement
  • VacuumRelation — individual relation in VACUUM → Loc covers relation reference
  • ClusterStmt — CLUSTER t USING myidx → Loc covers full statement
  • ReindexStmt — REINDEX TABLE t → Loc covers full statement
  • VariableSetStmt — SET search_path TO public → Loc covers full statement
  • VariableShowStmt — SHOW search_path → Loc covers full statement
  • AlterSystemStmt — ALTER SYSTEM SET max_connections = 200 → Loc covers full statement
  • ConstraintsSetStmt — SET CONSTRAINTS ALL DEFERRED → Loc covers full statement
  • DropStmt — DROP TABLE t → Loc covers full statement
  • DropOwnedStmt — DROP OWNED BY myrole → Loc covers full statement
  • DropSubscriptionStmt — DROP SUBSCRIPTION mysub → Loc covers full statement
  • DropTableSpaceStmt — DROP TABLESPACE mytbs → Loc covers full statement
  • TruncateStmt — TRUNCATE t → Loc covers full statement

Phase 5: Investigation Nodes

5.1 Nodes Without Parser Creation Sites

Targets: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go, investigation required Shared: pg/ast/parsenodes.go, pg/ast/loc.go, pg/ast/outfuncs.go Proof: go test ./pg/parser/... ./pg/parsertest/... -run Loc

  • FromExpr — N/A: planner-internal only; not created in parser (only in pg/catalog/query.go)
  • SetOperationStmt — N/A: planner-internal only; parser creates SelectStmt, analyze.go transforms to SetOperationStmt
  • WindowClause — N/A: planner-internal only; parser creates WindowDef, analyze.go transforms to WindowClauseQ
  • SortGroupClause — N/A: planner-internal only; created exclusively in pg/catalog/analyze.go
  • JsonReturning — N/A: struct exists but is never instantiated; parser uses JsonOutput instead