Find everywhere a record is used
Adding a field to a record looks harmless, but anything that depends on the record’s exact columns
can break: a SELECT * in an Application Engine program, or an INSERT without a column list.
Before you make the change, find everything that uses the record, and check each one. AI Assist
finds the uses, and the LLM reads each one to decide whether the change affects it.
You’ll use: find_references,
search_code,
describe_app_engine, and
describe_record.
We're adding a ZZ_TRAIN_HOURS field to the ZZ_TRAIN_REQ record.Find everything that uses the record, and tell me what would needto change.What happens
Section titled “What happens”-
find_referenceswith{"type": "record", "name": "ZZ_TRAIN_REQ"}lists the definitions that refer to the record: two pages, and three queries, one of them public. The empty groups matter too: no component uses the record as its search record, and no record uses it as a prompt table or subrecord.Result {"type": "record","name": "ZZ_TRAIN_REQ","pages": ["ZZ_TRAIN_APPR", "ZZ_TRAIN_REQ"],"searchRecordFor": [],"promptTableFor": [],"subrecordOf": [],"relatedLanguageRecordFor": [],"auditRecordFor": [],"queries": {"public": ["ZZ_TRAIN_REQ_STATUS"],"privateCount": 2},"truncated": false} -
search_codewith{"text": "ZZ_TRAIN_REQ"}finds the record’s name in code, in seven places: two PeopleCode programs, theZZ_TRN_PEND_VWview, and four statements in two Application Engine programs. One of them is inZZ_TRN_ARCH, a batch program that’s easy to forget when you change the component:One of the matches (abbreviated) {"source": "sql","sqlType": "app_engine","appEngine": "ZZ_TRN_ARCH.MAIN.Step01","line": 2,"snippet": "SELECT * FROM PS_ZZ_TRAIN_REQ"} -
describe_app_enginewith{"program": "ZZ_TRN_ARCH"}shows the whole statement. The LLM needs it because the snippet is only the matching line, and aSELECT *can be harmless on its own. The statement copies closed requests into a history table:ZZ_TRN_ARCH.MAIN.Step01 INSERT INTO PS_ZZ_TRAIN_HISTSELECT * FROM PS_ZZ_TRAIN_REQWHERE ZZ_TRAIN_STATUS IN ('C', 'D') -
describe_recordforZZ_TRAIN_HISTshows that it has the same fields asZZ_TRAIN_REQ, in the same order, which is why the statement works today.
What you get
Section titled “What you get”Adding
ZZ_TRAIN_HOURStoZZ_TRAIN_REQOne statement would fail:
ZZ_TRN_ARCH.MAIN.Step01. It copies rows withINSERT INTO PS_ZZ_TRAIN_HIST SELECT * FROM PS_ZZ_TRAIN_REQ, which works only while the two tables have the same columns in the same order. With the new column, the select returns one more value than the history table has columns, and Oracle Database rejects the insert with ORA-00913: too many values.The fix: rewrite the statement with the
%InsertSelectmeta-SQL construct. It builds the column list from the fields of the insert record,ZZ_TRAIN_HIST, and selects the fields of the same name fromZZ_TRAIN_REQ, so the statement keeps working when either record gains a field. If the history should keep the hours too, addZZ_TRAIN_HOURStoZZ_TRAIN_HISTas well, and%InsertSelectcopies it without further changes.No change needed for the other uses:
- Pages
ZZ_TRAIN_REQandZZ_TRAIN_APPRdisplay the record’s fields. Add the new field to them only if users should see the hours.- Queries select fields by name, so the public query
ZZ_TRAIN_REQ_STATUSand the two private queries aren’t affected.ZZ_TRAINING_REQ.GBL.SavePreChangecounts an employee’s pending requests.ZZ_TRAIN_REQ.COURSE.FieldChangesets the request’s fee from the course table.- The
ZZ_TRN_PEND_VWview selects three columns by name.ZZ_TRN_LOAD.MAIN.Step01selects approved requests, by column name.ZZ_TRN_LOAD.LOAD_ROW.Step02sets a request’s status to C.ZZ_TRN_ARCH.MAIN.Step02deletes the requests that Step01 copied.When you add the field, build
ZZ_TRAIN_REQwith the Alter Tables option in every database you move it to. The component reads every field of the record, so it fails until the table has the new column.
The LLM also drafts the new statement:
%InsertSelect(ZZ_TRAIN_HIST, ZZ_TRAIN_REQ A) FROM %Table(ZZ_TRAIN_REQ) A WHERE A.ZZ_TRAIN_STATUS IN ('C', 'D')%InsertSelect writes the INSERT and SELECT parts of the statement, but not the FROM
clause, so the statement still names the table it selects from.
Check the answer
Section titled “Check the answer”- Compare with Find Definition References. Open
ZZ_TRAIN_REQin Application Designer, and choose Edit > Find Definition References. It lists the definitions that refer to the record, so you can check that the answer missed nothing. - Test in development. Add the field, build the record, and then save a request in the
component and run
ZZ_TRN_ARCH, before you migrate anything.
Go further
Section titled “Go further”- “Show me every
SELECT *in our custom Application Engine programs.” - “List the definitions to add to the migration project for this change.”
- “What would break if we removed the FEE_AMT field from ZZ_TRAIN_REQ?”
