Project

General

Profile

Feature #9302

new reports for abbreviated field names and abbreviated table names

Added by Greg Shah over 1 year ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

100%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

9302_abbreviated_table_names.png (103 KB) Roger Borrello, 11/20/2024 04:42 PM

9302_roger_custom.png (191 KB) Roger Borrello, 11/20/2024 04:42 PM

History

#1 Updated by Greg Shah over 1 year ago

Please create 2 reports for:

  • Abbreviated Field Names
  • Abbreviated Table Names

You will need to create 2 helper functions to calculate this, since it will take some variables to store state. You can see the basic idea in rules/progress/eliminate_field_abbreviations.xml. We would use a similar idea to detecting abbreviated table names.

Once we have the helpers, please add reports for each of these. You can prototype them using the Custom Reports feature. Once they are working, move them into rules/reports/profile.rpt. I'll review it. Test it in Hotel GUI. If OK, we merge it quickly.

#2 Updated by Roger Borrello over 1 year ago

In reports.rules, there is a recent addition for nested finds:

      <!-- check if annotation "nested_find" is present -->
      <function name="nested_find">
         <parameter name="target"       type="com.goldencode.ast.Aast" />
         <return    name="isNestedFind" type="java.lang.Boolean" />

         <rule>isNestedFind = false</rule>
         <rule>target.isAnnotation("nested_find")
            <action>isNestedFind = true</action>
         </rule>
      </function>

      <!-- classify type of nested find -->
      <function name="type_nested_find_classify">
         <parameter name="target"   type="com.goldencode.ast.Aast" />
         <return    name="findType" type="java.lang.String" />

         <rule>downPath(target, prog.record_phrase, prog.kw_where)
            <action>findType = "WHERE"</action>
         </rule>

         <rule>target.getImmediateChild(prog.KW_FIRST, null) != null
            <action>findType = "FIRST"</action>
         </rule>

         <rule>target.getImmediateChild(prog.KW_LAST, null) != null
            <action>findType = "LAST"</action>
         </rule>

         <rule>target.getImmediateChild(prog.KW_NEXT, null) != null
            <action>findType = "NEXT"</action>
         </rule>

         <rule>target.getImmediateChild(prog.KW_PREV, null) != null
            <action>findType = "PREV"</action>
         </rule>

         <rule>target.getImmediateChild(prog.KW_CURRENT, null) != null
            <action>findType = "CURRENT"</action>
         </rule>
      </function>

Could this be similar, if there is an annotation about abbreviated fields and tables? I didn't see any such annotations in eliminate_field_abbreviations.xml but I'm guessing a similar find_abbreviations.xml could add them appropriately? Then the report would "report" them?

#3 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

Please create 2 reports for:

  • Abbreviated Field Names
  • Abbreviated Table Names

You will need to create 2 helper functions to calculate this, since it will take some variables to store state. You can see the basic idea in rules/progress/eliminate_field_abbreviations.xml. We would use a similar idea to detecting abbreviated table names.

I tried to catch the use of eliminate_field_abbreviations.xml by adding a printf:

         <!-- match all field references -->
         <rule>evalLib("fieldtype", type)
            <action>
               printf("eliminate_field_abbreviations: Found fieldtype %s\n", this.dumpTree())
            </action>

And updating rates-report.p in hotel_chui to abbreviate a field name:
def temp-table t-floor field floor like room.floo.

instead of:
def temp-table t-floor field floor like room.floor.

First, I'm not sure if this is how we'd come across an ambiguous field name, and second, I can't even see any use of eliminate_field_abbreviations.xml in my grep across FWD.

#4 Updated by Greg Shah over 1 year ago

eliminate_field_abbreviations.xml isn't used in any conversion or report. It just shows some example code that implements ambiguous field name detection.

I expect you to write a new set of functions using a similar technique and call them as needed during report processing.

Could this be similar, if there is an annotation about abbreviated fields and tables? I didn't see any such annotations in eliminate_field_abbreviations.xml but I'm guessing a similar find_abbreviations.xml could add them appropriately? Then the report would "report" them?

Yes, you could do that. You'd have to set those during early annotations. Then the reports are simple.

#5 Updated by Roger Borrello over 1 year ago

Is this an example of an ambiguous field name?

def temp-table t-floor field floor like room.floo.

I can ask the customer for some, as well, to make sure I have valid testcases.

#6 Updated by Greg Shah over 1 year ago

  • Subject changed from new reports for ambiguous field names and ambiguous table names to new reports for abbreviated field names and abbreviated table names

Sorry, I should not have used "ambiguous". That is something completely different. We are needing to identify abbreviated names.

#7 Updated by Greg Shah over 1 year ago

If a table is named rogers-fav, then an abbreviated name would be "rog" or "roge" or "roger" or...

The concept is the same for fields.

#8 Updated by Roger Borrello over 1 year ago

Note from customer:

Erm I think just database tables?

slli-claim-goods-val which should be slli-claim-goods-value

slld-part-sett which should be slld-part-settl

stco-cust-call which should be stco-cust-calloff

stdo-call which should be stdo-calloff

Some of those programs have multiple instances.

#9 Updated by Roger Borrello over 1 year ago

Parsing wouldn't work if the names were ambiguous, correct? In other words, tables in the DB are "best-dream" and "best-nightmare" but code has "best" won't work, so I can trust the annotations such that checking text against the correct spot in schemaname won't steer me wrong.

I plan to determine if the length of the text doesn't match the length of the appropriate location in schemaname, it is an abbreviation.

#10 Updated by Greg Shah over 1 year ago

Yes, forget about ambiguous. The issue here is abbreviations.

#11 Updated by Greg Shah over 1 year ago

I plan to determine if the length of the text doesn't match the length of the appropriate location in schemaname, it is an abbreviation.

OK

Recall that you must handle the fact that the text can be qualified (db.table.field, db.table, table.field) or not qualified (table, field). ALSO: there is a special treat in which 4GL code can insert whitespace in between the table and field of a qualified field name. You should carefully read the eliminate_field_abbreviations.xml rule set, because it does handle all of those cases.

#12 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

Recall that you must handle the fact that the text can be qualified (db.table.field, db.table, table.field) or not qualified (table, field). ALSO: there is a special treat in which 4GL code can insert whitespace in between the table and field of a qualified field name. You should carefully read the eliminate_field_abbreviations.xml rule set, because it does handle all of those cases.

Yes, I saw the use of the "original-text" annotation:

            <!-- some qualified field references can have spaces between the qualifier and
                 field; this was removed during parsing, but remembered for future use -->
            <action>oritxt = getNoteString("original-text")</action>

If I am adding the call to the helper which will be adding an abbreviation annotation in early_annotations.xml, will the "original-text" annotation already be there? I figured I'd add at the bottom of early_annotations, but is that too early?

#13 Updated by Greg Shah over 1 year ago

The original-text annotation comes from the parser, so it will already be there if it is going to be there.

To be clear: it is not always there. We only add it if the parser itself is rewriting/changing the text, then we save off the original contents of the node in original-text. So just make sure that you don't rely upon that there. Deal with it when it is there and deal with it when it is not there.

#14 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

The original-text annotation comes from the parser, so it will already be there if it is going to be there.

To be clear: it is not always there. We only add it if the parser itself is rewriting/changing the text, then we save off the original contents of the node in original-text. So just make sure that you don't rely upon that there. Deal with it when it is there and deal with it when it is not there.

The example uses it, if it is there, and the text if not:

            <!-- some qualified field references can have spaces between the qualifier and
                 field; this was removed during parsing, but remembered for future use -->
            <action>oritxt = getNoteString("original-text")</action>

            <!-- default to the text that exists in the node -->
            <rule>oritxt == null
               <action>oritxt = text</action>
               <action on="false">hadori = true</action>
            </rule>

Picturing what the 4GL looks like if there are spaces between the table and field is odd... is there still a period, or does the whitespace replace the period?

#15 Updated by Greg Shah over 1 year ago

From our parser:

   /**
    * Use lookahead to determine if the qualified database name quirk is
    * present in the given tokens. In such a case, the source code has
    * whitespace between the record name and the DOT and/or whitespace
    * between the DOT and the fieldname portions but Progress treats this as
    * a properly qualified field name.
    *
    * @param    tok1
    *           First token, typically LT(1).
    * @param    tok2
    *           Second token, typically LT(2).
    * @param    tok3
    *           Third token, typically LT(3).
    *
    * @return   true if the name quirk is detected.
*/
private boolean isQualifiedFieldNameQuirk(Token tok1,
Token tok2,
Token tok3)

#16 Updated by Roger Borrello over 1 year ago

So record.field can be record. field or record .field or record . field ? That's evil.

#17 Updated by Constantin Asofiei over 1 year ago

Roger, I don't think the 'quirk' with the space before the field is relevant for this report.

See this example:

find first boo.
message boo.is.
message boo. isb.

which produces this:

    <ast col="0" id="17179869186" line="0" text="statement" type="STATEMENT">
      <ast col="1" id="17179869187" line="1" text="find" type="KW_FIND">
        <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
        <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
        <ast col="6" id="17179869189" line="1" text="first" type="KW_FIRST"/>
        <ast col="0" id="17179869191" line="0" text="record phrase" type="RECORD_PHRASE">
          <ast col="12" id="17179869192" line="1" text="boo" type="TABLE">
            <annotation datatype="java.lang.String" key="dbname" value="fwd"/>
            <annotation datatype="java.lang.String" key="schemaname" value="fwd.book"/>
            <annotation datatype="java.lang.String" key="db_signature" value="int|char|char|char|int|dec|char|date|int|int|dec|char%UP^book-id^0|int%^author-id^8|int%U^isbn^3|char%^pub-date^7|date%^publisher^2|char"/>
            <annotation datatype="java.lang.String" key="bufname" value="fwd.book"/>
            <annotation datatype="java.lang.Long" key="recordtype" value="12"/>
          </ast>
        </ast>
      </ast>
    </ast>
    <ast col="0" id="17179869195" line="0" text="statement" type="STATEMENT">
      <ast col="1" id="17179869196" line="2" text="message" type="KW_MSG">
        <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
        <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
        <ast col="0" id="17179869198" line="0" text="" type="CONTENT_ARRAY">
          <ast col="0" id="17179869199" line="0" text="expression" type="EXPRESSION">
            <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
            <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
            <ast col="9" id="17179869200" line="2" text="boo.is" type="FIELD_CHAR">
              <annotation datatype="java.lang.String" key="columnlabel" value="&quot;ISBN&quot;"/>
              <annotation datatype="java.lang.String" key="dbname" value="fwd"/>
              <annotation datatype="java.lang.String" key="format" value="&quot;x(15)&quot;"/>
              <annotation datatype="java.lang.Long" key="oldtype" value="6"/>
              <annotation datatype="java.lang.String" key="bufname" value="fwd.book"/>
              <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
              <annotation datatype="java.lang.String" key="schemaname" value="fwd.book.isbn"/>
              <annotation datatype="java.lang.String" key="name" value="boo.is"/>
              <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
              <annotation datatype="java.util.ArrayList" key="label">
                <listitem datatype="java.lang.String" value="&quot;ISBN&quot;"/>
              </annotation>
              <annotation datatype="java.lang.Long" key="recordtype" value="12"/>
              <annotation datatype="java.lang.Long" key="type" value="413"/>
            </ast>
          </ast>
        </ast>
      </ast>
    </ast>
    <ast col="0" id="17179869203" line="0" text="statement" type="STATEMENT">
      <ast col="1" id="17179869204" line="3" text="message" type="KW_MSG">
        <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
        <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
        <ast col="0" id="17179869206" line="0" text="" type="CONTENT_ARRAY">
          <ast col="0" id="17179869207" line="0" text="expression" type="EXPRESSION">
            <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
            <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
            <ast col="9" id="17179869208" line="3" text="boo.isb" type="FIELD_CHAR">
              <annotation datatype="java.lang.String" key="columnlabel" value="&quot;ISBN&quot;"/>
              <annotation datatype="java.lang.String" key="dbname" value="fwd"/>
              <annotation datatype="java.lang.String" key="format" value="&quot;x(15)&quot;"/>
              <annotation datatype="java.lang.Long" key="oldtype" value="2977"/>
              <annotation datatype="java.lang.String" key="bufname" value="fwd.book"/>
              <annotation datatype="java.lang.String" key="support_level-byrule" value="gaps/gap_analysis_marking.xml:435"/>
              <annotation datatype="java.lang.String" key="schemaname" value="fwd.book.isbn"/>
              <annotation datatype="java.lang.String" key="name" value="boo.isb"/>
              <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
              <annotation datatype="java.util.ArrayList" key="label">
                <listitem datatype="java.lang.String" value="&quot;ISBN&quot;"/>
              </annotation>
              <annotation datatype="java.lang.String" key="original-text" value="boo. isb"/>
              <annotation datatype="java.lang.Long" key="recordtype" value="12"/>
              <annotation datatype="java.lang.Long" key="type" value="413"/>
            </ast>
          </ast>
        </ast>
      </ast>
    </ast>

There is schemaname with the resolved field and the text at the FIELD ast (FIELD_CHAR) (or the name annotation) is what was resolved to.

There is com.goldencode.p2j.schema.EntityName which can be used to parse a string representing a field, table or database.

If the AST text and the schemaname annotation is not the same, then use EntityName to see what has been abbreviated (the field? table? or schema?).

#18 Updated by Greg Shah over 1 year ago

So record.field can be record. field or record .field or record . field ?

Yes

That's evil.

Yes

#19 Updated by Greg Shah over 1 year ago

I don't think the 'quirk' with the space before the field is relevant for this report.

Yes, you're right. We had to worry about it for eliminate_field_abbreviations.xml because we were editing the original text to anti-parse. We don't need that here.

#20 Updated by Roger Borrello over 1 year ago

If I understand correctly, I can use the schemaname to breakdown the table and field. My current helper for fields looks like:

<rule-set>

   <!-- variables -->
   <variable name="sname"           type="java.lang.String" />
   <variable name="tname"           type="java.lang.String" />
   <variable name="fname"           type="java.lang.String" />
   <variable name="clean"           type="java.lang.String" />
   <variable name="abbrev"          type="java.lang.String" />
   <variable name="oritxt"          type="java.lang.String" />
   <variable name="fdot"            type="java.lang.Integer" />
   <variable name="abbrev_len"      type="java.lang.Integer" />
   <variable name="edits"           type="java.lang.Boolean" />
   <variable name="hadori"          type="java.lang.Boolean" />

   <walk-rules>

      <!-- match all field references -->
      <rule>evalLib("fieldtype", type)

         <!-- read the fully qualified schema name annotation -->
         <action>sname = getNoteString("schemaname")</action>

         <rule>sname != null

            <!-- parse the table portion of the canonical name -->
            <action>fdot = sname.indexOf(".")</action>
            <rule>fdot &gt;= 0
               <action>tname = sname.substring(fdot + 1)</action>
               <!-- <action>printf("Found tname=%s in sname=%s, text=%s\n", tname, sname, text)</action> -->
               <action on="false">printf("Missing qualifier in schemaname annotation!  See %s\n", this.dumpTree())</action>
               <action on="false">tname = ""</action>
            </rule>

            <!-- parse the field portion of the canonical name -->
            <action>fdot = sname.lastIndexOf(".")</action>
            <rule>fdot &gt;= 0
               <action>fname = sname.substring(fdot + 1)</action>
               <action on="false">fname = ""</action>
            </rule>

            <!-- parse the field portion of the field reference -->
            <action>fdot = text.lastIndexOf(".")</action>
            <rule>fdot &gt;= 0
               <action>abbrev = text.substring(fdot + 1).trim()</action>

               <!-- unqualified field name (probably could use text directly here) -->
               <action on="false">abbrev = text</action>
            </rule>

            <!-- detect if an abbreviation is in use in the field portion -->
            <rule>!fname.isEmpty() and fname.length() != abbrev.length()
               <action>edits = true</action>

               <rule>fdot &gt;= 0
                  <!-- qualified form -->
                  <action>clean = sprintf("%s.%s", text.substring(0, fdot), fname)</action>
                  <action>
                     printf("ANNOTATING qualfied name from %s to %s at %s.\n", text, clean, this.dumpTree())
                  </action>

                  <!-- unqualified form -->
                  <action on="false">clean = fname</action>
                  <action on="false">
                     printf("ANNOTATING UNqualfied name from %s to %s at %s.\n", text, clean, this.dumpTree())
                  </action>
               </rule>

               <!-- Enter an annotation -->
               <action>copy.putAnnotation("abbreviated-field", clean)</action>
            </rule>

            <action on="false">
               printf("Missing schemaname annotation!  See %s\n", this.dumpTree())
            </action>
         </rule>
      </rule>

   </walk-rules>

</rule-set>

There's some extra parsing in there. But in order to optimize this to handle both table names and field names, what should the condition be for entering the parsing, besides evalLib("fieldtype", type)? Can I just check for getNoteString("schemaname") to not be null, then determine if any of the parts (table or field) in the text are not the same length as the equivalent part of the schemaname?

#21 Updated by Greg Shah over 1 year ago

evalLib("fieldtype", type) is correct for looking at fields. Use evalLib("record_types") to look at table/buffer references. You may have some common code but it won't be 100% common.

DO NOT just look for schemaname annotations. They can be anywhere.

#22 Updated by Constantin Asofiei over 1 year ago

Something else to mention: table abbreviations can appear in field references, too - see my example. So for evalLib("fieldtype", type) case you need to check for both the field part and the table part in the AST text.

Instead of looking for the dot, try using EntityName - that has everything:

   <variable name="en1" type="com.goldencode.p2j.schema.EntityName" />
   <action>en1 = create("com.goldencode.p2j.schema.EntityName", 1, schemaname)</action>  <!-- use 2 for 'fieldType', 1 for RECORD reference -->
   <!-- when parsing field, database and table may be null -->
   <!-- when parsing record, database can be null -->
   <action>printfln("%s %s %s", en1.getDatabase(), en1.getTable(), en1.getField())</action>

Also, from what I see, names for explicit buffer definitions can't be abbreviated.

#23 Updated by Roger Borrello over 1 year ago

In trying to enlarge my testcase, it obvious I can't just hack out the tail end of table names and field names. For example:

def temp-table t-room-type field type like room.type-of-room field name as char format "x(20)"  label "Room Type".

I can change like room.type-of-room to like room.type-of-ro, but not like roo.type-of-ro as we get unexpected token: roo.type-of-ro

This seems contrary to Constantin's testcase where I assume he's using "book" abbreviated to "boo" from the p2j_test.df database. What am I missing?

#24 Updated by Greg Shah over 1 year ago

Make sure that any abbreviation uniquely references a single table or a single field (of a single table). So: roo can't be used as a table name if there are tables room-type and room-rate.

#25 Updated by Roger Borrello over 1 year ago

While the use of EntityName is great for getting the precise name of the DB/table/field, trying to determine if the table/field located in the current node of the tree contains a db qualifier and/or the field contains a table qualifier doesn't seem to be as precise. If there are 2 '.' characters, that's a good indication that there are DB/table qualifiers. But if there is only one, I might be at a loss for whether it is a db-qualified table or a table-qualified field.

Right now I am just relying upon <rule>evalLib("fieldtype", type). Does that disqualify a db-qualified table as what might be in "text"?

Also, I have branch 9302a created to be able to review my code. Please do so, and I will pick this up when I am back

#26 Updated by Roger Borrello over 1 year ago

The code that is checked in does find abbreviated db/table/field in the fieldtype, and annotates:

          <ast col="24" id="51539607864" line="29" text="hotel.rat.type-of-room" type="FIELD_INT">
            <annotation datatype="java.lang.Boolean" key="is_meta" value="false"/>
            <annotation datatype="java.lang.String" key="schemaname" value="hotel.rate.type-of-room"/>
            <annotation datatype="java.lang.String" key="columnlabel" value="&quot;Type of Room&quot;"/>
            <annotation datatype="java.lang.Boolean" key="possible_needs_buffer" value="true"/>
            <annotation datatype="java.lang.String" key="format" value="&quot;&gt;&gt;9&quot;"/>
            <annotation datatype="java.lang.Long" key="type" value="421"/>
            <annotation datatype="java.lang.String" key="uniquename" value="hotel.rate_hotel.rate"/>
            <annotation datatype="java.util.ArrayList" key="label">
              <listitem datatype="java.lang.String" value="&quot;Type of Room&quot;"/>
            </annotation>
            <annotation datatype="java.lang.String" key="name" value="hotel.rat.type-of-room"/>
            <annotation datatype="java.lang.Long" key="oldtype" value="6"/>
            <annotation datatype="java.lang.Long" key="recordtype" value="12"/>
            <annotation datatype="java.lang.String" key="fieldtype-abbreviated" value="hotel.rate.type-of-room"/>
            <annotation datatype="java.lang.String" key="bufname" value="hotel.rate"/>
            <annotation datatype="java.lang.String" key="dbname" value="hotel"/>
            <annotation datatype="java.lang.String" key="bufrefkey" value="hotel.rate,hotel.rate,-1"/>
            <annotation datatype="java.lang.Long" key="bufreftype" value="18"/>
            <annotation datatype="java.lang.Long" key="support_level" value="16400"/>
          </ast>

But it doesn't always match up the number of qualifiers in the text with what is written in the annotation.

#27 Updated by Greg Shah over 1 year ago

If there are 2 '.' characters, that's a good indication that there are DB/table qualifiers.

A "good" indication? It is a 100% guarantee. Also, this can only happen in a field reference, not in a table reference.

But if there is only one, I might be at a loss for whether it is a db-qualified table or a table-qualified field.

This is never in doubt. The token type of the node tells you if this is a table or field reference.

Right now I am just relying upon <rule>evalLib("fieldtype", type). Does that disqualify a db-qualified table as what might be in "text"?

Yes, tables cannot be fields.

#28 Updated by Greg Shah over 1 year ago

Roger Borrello wrote:

The code that is checked in does find abbreviated db/table/field in the fieldtype, and annotates:
[...]

But it doesn't always match up the number of qualifiers in the text with what is written in the annotation.

There should be 2 possible annotations:

  • fieldname_abbreviated (only can occur in a field reference)
  • tablename_abbreviated (can occur in either a qualified field or any table reference)

#29 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

Yes, tables cannot be fields.

I think we are not communicating well. How do you see this annotated?

def var room-type like hotel.rat.type-of-room format ">>>,>>>,>>>".

Like this?
...
          <ast col="24" id="51539607864" line="29" text="hotel.rat.type-of-room" type="FIELD_INT">
            <annotation datatype="java.lang.String" key="fieldname_abbreviated" value="hotel.rate.type-of-room"/>
...

And:

def temp-table t-room-type field type like room.type-of-ro field name as char format "x(20)"  label "Room Type".

Like:
              <ast col="44" id="51539608187" line="48" text="room.type-of-ro" type="FIELD_INT">
                <annotation datatype="java.lang.String" key="fieldname_abbreviated" value="hotel.room.type-of-room"/>

or like:
              <ast col="44" id="51539608187" line="48" text="room.type-of-ro" type="FIELD_INT">
                <annotation datatype="java.lang.String" key="fieldname_abbreviated" value="room.type-of-room"/>

In other words, should the clean annotation match the level of qualifiers as the original code, or should it be fully qualified?

#30 Updated by Greg Shah over 1 year ago

Make fieldname_abbreviated a boolean. Same for tablename_abbreviated. It just tells someone that the field or table portion of the name is abbreviated. That is all we need for writing a report.

#31 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

Make fieldname_abbreviated a boolean. Same for tablename_abbreviated. It just tells someone that the field or table portion of the name is abbreviated. That is all we need for writing a report.

That will simplify things if the report doesn't need to show what the non-abbreviated name is.

How about my example of an abbreviated table name in the field reference... is that a tablename_abbreviated or fieldname_abbreviated?

#32 Updated by Greg Shah over 1 year ago

Roger Borrello wrote:

Greg Shah wrote:

Make fieldname_abbreviated a boolean. Same for tablename_abbreviated. It just tells someone that the field or table portion of the name is abbreviated. That is all we need for writing a report.

That will simplify things if the report doesn't need to show what the non-abbreviated name is.

The non-abbreviated name is already available in the schemaname annotation. If we need it for the report, we get it from there.

How about my example of an abbreviated table name in the field reference... is that a tablename_abbreviated or fieldname_abbreviated?

tablename_abbreviated

#33 Updated by Roger Borrello over 1 year ago

  • Status changed from New to WIP
  • % Done changed from 0 to 70

Please review branch 15555 as I believe I have a solution to both tables and fields (and databases) to be able to annotate abbreviations in all cases of fieldtype and record_types.

#34 Updated by Roger Borrello over 1 year ago

Roger Borrello wrote:

Please review branch 15555 as I believe I have a solution to both tables and fields (and databases) to be able to annotate abbreviations in all cases of fieldtype and record_types.

Please review from the perspective of fieldtype only, since I found that the record_types will need more special processing.

#35 Updated by Greg Shah over 1 year ago

Code Review Task Branch 9302a Revisions 15553 through 15555

I think you should separate the table and field processing. Your attempt to make it all common code is making the result:

  • harder to read/reason about
  • more fragile

The way you are using en1 = create("com.goldencode.p2j.schema.EntityName", 2, sname) is only for fields but you are also passing it the schemaname for tables (the evalLib("record_types") case). I don't think that is OK.

Similarly, you have extra code to detect if the two dot case is a field or a table, but the outer code already knows this. If evalLib("fieldtype", type) is true then it is a field and evalLib("record_types") is a table.

I would keep the field and table stuff separated but if you have some common code you can put it in functions.

Also: why do you have all your own code for parsing the names out? Please use EntityName to parse the names instead of writing your own.

#36 Updated by Roger Borrello over 1 year ago

  • % Done changed from 70 to 90
  • Status changed from WIP to Review

Greg Shah wrote:

Code Review Task Branch 9302a Revisions 15553 through 15555

I think you should separate the table and field processing. Your attempt to make it all common code is making the result:

  • harder to read/reason about
  • more fragile

The opportunity to do all abbreviation annotations in one pass through the code would seem to be more streamline. I can make the code easier to read, but what TRPL code is easy to read? :-)

The way you are using en1 = create("com.goldencode.p2j.schema.EntityName", 2, sname) is only for fields but you are also passing it the schemaname for tables (the evalLib("record_types") case). I don't think that is OK.

I am not doing that anymore. The 1 or 2 is based upon whether it is fieldtype or record_types. That's the only difference in the code. In fact, the 2 are exactly the same, save for the default value of the entype.

Similarly, you have extra code to detect if the two dot case is a field or a table, but the outer code already knows this. If evalLib("fieldtype", type) is true then it is a field and evalLib("record_types") is a table.

This is true, but the TRPL rule's capabilities in the if/else if/else if/else is very nested, unless there is some way to make it more structured.

I would keep the field and table stuff separated but if you have some common code you can put it in functions.

I'd like to do that, but basically the whole thing is a function. I can either do that, or just use one, and determine whether it is fieldtype or record_type and just branch the code in the 1 place where there is different logic.

Also: why do you have all your own code for parsing the names out? Please use EntityName to parse the names instead of writing your own.

This code does the parsing of the entity:

            <action>en1 = create("com.goldencode.p2j.schema.EntityName", entype, sname)</action>  <!-- use 2 for 'fieldType', 1 for RECORD reference -->
            <!-- when parsing field, database and table may be null -->
            <!-- when parsing record, database can be null -->
            <action>s_dname = en1.getDatabase()</action>
            <action>s_tname = en1.getTable()</action>
            <action>s_fname = en1.getField()</action>

When we get to the text, how can I use EntityName to parse? I need a leg up on that, because it is kind of free-form when things are abbreviated in the text.

I have working reports (at least for Hotel ChUI) checked into revision 15556. I can back off on the single abbrev_check.rules, as is implemented, and try to work to separate them, but I don't know that it is worth the time, unless something is glaringly wrong.

#37 Updated by Greg Shah over 1 year ago

When we get to the text, how can I use EntityName to parse? I need a leg up on that, because it is kind of free-form when things are abbreviated in the text.

You used it to parse the schemaname (in the sname variable) like this:

en1 = create("com.goldencode.p2j.schema.EntityName", 2, sname)

You can use it to parse text like this:

en2 = create("com.goldencode.p2j.schema.EntityName", <entity_type>, text)

Delete all of your parsing code and leverage the common code from EntityName. Then separate the processing so that you don't have extra logic figuring out things we already know (like whether we are a field or table).

I think the result will have much less code and will be easier to read.

#38 Updated by Roger Borrello over 1 year ago

I am not sold on EntityName, partly because there isn't many solid examples, and also it blew up on Hotel GUI. The 4GL in rooms-frame.w is:

     OPEN QUERY roomsBrowse FOR EACH room NO-LOCK, 
        EACH room-type OF hotel.room NO-LOCK 
        WHERE room.floor = val.   

which threw: Caused by: java.lang.IllegalArgumentException: Invalid table name: hotel.room.floor:
entype=1, sname=hotel.room.floor: tree=room.floor [FIELD_INT]:300647723009 @3518:15

Elapsed job time:  00:00:00.299
ERROR:
com.goldencode.p2j.pattern.TreeWalkException: ERROR!  Active Rule:
-----------------------
      RULE REPORT      
-----------------------
Rule Type :   WALK
Source AST:  [ room.floor ] BLOCK/PROCEDURE/BLOCK/STATEMENT/KW_IF/KW_THEN/INNER_BLOCK/BLOCK/STATEMENT/OPEN_QUERY/KW_FOR/RECORD_PHRASE/KW_WHERE/EXPRESSION/EQUALS/FIELD_INT/ @3518:15 {300647723009}
Copy AST  :  [ room.floor ] BLOCK/PROCEDURE/BLOCK/STATEMENT/KW_IF/KW_THEN/INNER_BLOCK/BLOCK/STATEMENT/OPEN_QUERY/KW_FOR/RECORD_PHRASE/KW_WHERE/EXPRESSION/EQUALS/FIELD_INT/ @3518:15 {300647723009}
Condition :  en1 = create("com.goldencode.p2j.schema.EntityName", entype, sname)
Loop      :  false
--- END RULE REPORT ---

So the call to en1 = create("com.goldencode.p2j.schema.EntityName", entype, sname) with entype=1 and sname=hotel.room.floor throws an error.

#39 Updated by Roger Borrello over 1 year ago

Roger Borrello wrote:

I am not sold on EntityName, partly because there isn't many solid examples, and also it blew up on Hotel GUI. The 4GL in rooms-frame.w is:
[...]
which threw: Caused by: java.lang.IllegalArgumentException: Invalid table name: hotel.room.floor:
[...]

So the call to en1 = create("com.goldencode.p2j.schema.EntityName", entype, sname) with entype=1 and sname=hotel.room.floor throws an error.

I had to check on the entype each walk:

         <rule>evalLib("record_types")
            <action>entype = 1</action>
            <action on="false">entype = 2</action>
         </rule>

#40 Updated by Roger Borrello over 1 year ago

  • % Done changed from 90 to 100

Greg Shah wrote:

You can use it to parse text like this:

en2 = create("com.goldencode.p2j.schema.EntityName", <entity_type>, text)

Done... revision 15557 ready for review.

#41 Updated by Roger Borrello over 1 year ago

The customer's application ran reports fine, and I was able to see the number of table/field abbreviations. My guess is that trying to include database abbreviations is just a waste. I can provide the reports for analysis to the customer, while we further refine this task.

#42 Updated by Greg Shah over 1 year ago

My guess is that trying to include database abbreviations is just a waste.

I would say so, since database names cannot be abbreviated in the 4GL.

I can provide the reports for analysis to the customer, while we further refine this task.

Yes, that makes sense.

#43 Updated by Greg Shah over 1 year ago

Code Review Task Branch 9302a Revisions 15556 and 15557

This is much better.

1. Unless you have found that database names can be abbreviated in OE (I think they cannot), please remove the database abbreviations report and code.

2. I'm surprised that we don't have to put more code in for the condition. Using condition="this.getAnnotation("tablename_abbreviated")" will just return null for nearly every AST in a project. Even if this works without problems, I prefer (for performance reasons) to use a condition like this:

condition="evalLib("record_types_rel", this) and this.getAnnotation("tablename_abbreviated")"

And you would use the equivalent for fields. The point: don't do an annotations map lookup on every AST node in the project when 99.9999% of the time you can't possibly get a match.

3. Please change title="Abbreviated Table Name" to title="Abbreviated Table Names" (and the same for the field report).

#44 Updated by Constantin Asofiei over 1 year ago

Greg Shah wrote:

condition="evalLib("record_types_rel", this) and this.getAnnotation("tablename_abbreviated")"

Tables can be abbreviated when used in field references, so this should include evalLib("fieldtype", this.type), too.

#45 Updated by Roger Borrello over 1 year ago

I'm trying to keep this moving along in my spare time, so I'm still peeking at emails. See revision 15563.

The use of record_types_rel threw me... should I be using that in the check for abbreviations instead of evalLib("record_types")?

So the report now looks like this, although I'm pressed for time, and haven't been able to test. I'll kick off reports to test.

   <report
      condition="evalLib((&quot;record_types_rel&quot;, this) or evalLib(&quot;fieldtype&quot;, this.type)) and this.getAnnotation(&quot;tablename_abbreviated&quot;)" 
      dumpType="parser" 
      multiplexExpr="getNoteString(&quot;schemaname&quot;)" 
      title="Abbreviated Table Names" 
      tags="Database"/>
   <report
      condition="evalLib(&quot;fieldtype&quot;, this.type) and this.getAnnotation(&quot;fieldname_abbreviated&quot;)" 
      dumpType="parser" 
      multiplexExpr="getNoteString(&quot;schemaname&quot;)" 
      title="Abbreviated Field Names" 
      tags="Database"/>

#46 Updated by Greg Shah over 1 year ago

The use of record_types_rel threw me... should I be using that in the check for abbreviations instead of evalLib("record_types")?

You can look them up to answer your question.

So the report now looks like this, although I'm pressed for time, and haven't been able to test. I'll kick off reports to test.
[...]

This is good.

#47 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

So the report now looks like this, although I'm pressed for time, and haven't been able to test. I'll kick off reports to test.
[...]

This is good.

I did fix a bug in revisions 15563 and 15564 where it was collecting some fields as tables. Now it looks more accurate.

#48 Updated by Roger Borrello over 1 year ago

I have a good report that aggregates all the details so an export contains all the matches:

   <report
      condition="(evalLib(&quot;record_types_rel&quot;, this) or evalLib(&quot;fieldtype&quot;, this.type)) and (this.getAnnotation(&quot;tablename_abbreviated&quot;) != null)" 
      dumpType="simple" 
      multiplexExpr="'Abbreviated Table Names'" 
      title="Abbreviated Table Names" 
      tags="Database"/>

However, when you drill down, I'd like to set the match expression to this.text.concat(" ABBREV OF ").concat(getNoteString("schemaname")) so that meaningful information is contained in the export. I can actually set this up in a Custom Report by setting the "Match Expression".

Is there a way to set the match expression in the profile.rpt?

#49 Updated by Greg Shah over 1 year ago

Is there a way to set the match expression in the profile.rpt?

Instead of setting dumpType, you set dumpExpr. But I don't think we want this "single bucket" version as a standard report.

#50 Updated by Roger Borrello over 1 year ago

Greg Shah wrote:

Instead of setting dumpType, you set dumpExpr.

That works great... this is a very useful report.

But I don't think we want this "single bucket" version as a standard report.

I am not sure what the benefit of the "multiple buckets" report would be. I don't see any benefit to seeing how many abbreviations collections there are. The important thing is by file, which still have in the "single bucket" version.

I'd propose to just keep the collection version, especially for this report where it is more important to setup the export, which is more useful than online viewing.

#51 Updated by Greg Shah over 1 year ago

The multiple buckets version is the useful case for actually interacting with the report online.

If we need this kind of aggregation, we will add it as a general export feature. We aren't going to add "single bucket" versions of every report.

#52 Updated by Roger Borrello over 1 year ago

That's fine. We'll just document the Custom Reports:

Field Value
Report Type code
Report Title Abbreviated Table Names (for export)
Condition Expression (evalLib("record_types_rel", this) or evalLib("fieldtype", this.type)) and (this.getAnnotation("tablename_abbreviated") != null)
Multiplex Expression Collection
Category Tags Database
Match Text Format N/A
Match Expression this.text.concat(" ABBREV OF ").concat(getNoteString("schemaname"))
Match Text Level N/A
Field Value
Report Type code
Report Title Abbreviated Field Names (for export)
Condition Expression evalLib("fieldtype", this.type) and (this.getAnnotation("fieldname_abbreviated") != null)
Multiplex Expression Collection
Category Tags Database
Match Text Format N/A
Match Expression this.text.concat(" ABBREV OF ").concat(getNoteString("schemaname"))
Match Text Level N/A

#53 Updated by Roger Borrello over 1 year ago

There isn't anything left to do with this task. I've rebased the branch to 15577.

#54 Updated by Greg Shah over 1 year ago

  • Status changed from Review to Merge Pending

You can merge to trunk now.

#55 Updated by Roger Borrello over 1 year ago

Merge notification for task branch 9302a

Branch 9302a was merged to trunk as revision 15571 and archived.

  • Added reports for abbreviated field names and abbreviated table names. Ref. 9302.
  • In the native/makefile, added a comment to assist in calling makefile directly. Ref #6865.
  • In deploy_fwd.sh script updated to always setup version.properties

Rerun reports if you want to find abbreviated tables or fields in the 4GL.

#56 Updated by Greg Shah over 1 year ago

  • Status changed from Merge Pending to Closed

#57 Updated by Eugenie Lyzenko over 1 year ago

Roger,

Does it require reconversion?

#58 Updated by Roger Borrello over 1 year ago

Eugenie Lyzenko wrote:

Does it require reconversion?

No.

Also available in: Atom PDF