50 Things You May Not Know You Can Do With The 4GL Gus Bjrklund. - - PowerPoint PPT Presentation

50 things you may not know you can do with the 4gl
SMART_READER_LITE
LIVE PREVIEW

50 Things You May Not Know You Can Do With The 4GL Gus Bjrklund. - - PowerPoint PPT Presentation

50 Things You May Not Know You Can Do With The 4GL Gus Bjrklund. Progress. PUG Challenge Americas Westford, MA June 5 to 8, 2011 50 Things 1 Agenda A smrgsbord of large and small topics Having nothing to do with each other


slide-1
SLIDE 1

50 Things 1

50 Things You May Not Know You Can Do With The 4GL

Gus Björklund. Progress.

PUG Challenge Americas Westford, MA June 5 to 8, 2011

slide-2
SLIDE 2

50 Things 2

Agenda

  • A smörgåsbord of large and small topics
  • Having nothing to do with each other
  • In no particular order
slide-3
SLIDE 3

50 Things 3

Credit

  • I didn't think all this up myself.

– Greg Higgins, – Dmitri Levin, – Dustin Grau, – Tom Bascom, – Dan Foreman,

  • and others came up with some of these
slide-4
SLIDE 4

50 Things 4

Call a dynamic shared library function (Windows .DLL

  • r

UNIX/Linux .so)

slide-5
SLIDE 5

50 Things 5

define variable x as integer no-undo. procedure putenv external "/lib64/libc.so.6": define input parameter env as character. define return parameter x as long. end. run putenv( "XYZZY=pflugh", output x ). display os-getenv( "XYZZY" ).

  • s-command value( 'echo "$XYZZY"' ).

return.

Shared library call example

This code was gratuitously stolen from Tom Bascom. He has lots more.

slide-6
SLIDE 6

50 Things 6

Get Process Identifiers

slide-7
SLIDE 7

50 Things 7

define variable pid as character no-undo. input through "echo $PPID". import pid. input close.

Using input through

slide-8
SLIDE 8

50 Things 8

procedure getpid external "/usr/lib/glibc.so" cdecl: define return parameter pid as long no-undo. end procedure. /* then to use it: */ def var p as integer no-undo. p = getpid ().

Using UNIX/Linux C library call

slide-9
SLIDE 9

50 Things 9

procedure GetCurrentProcessId external "kernel32.dll": define return parameter pid as long. end procedure. def var p as integer no-undo. run GetCurrentProcessId (output p).

Using Windows kernel library call

slide-10
SLIDE 10

50 Things 10

def var p as integer no-undo. find first _myconnection no-lock. p = _myconnection._myconn-pid.

Using Database VST

slide-11
SLIDE 11

50 Things 11

Time Management

slide-12
SLIDE 12

50 Things 12

Date/Time related stuff

  • Data types

– DATE – DATETIME – DATETIME-TZ – INT64

  • Session attributes

– SESSION:TIMEZONE – SESSION:DISPLAY-TIMEZONE

slide-13
SLIDE 13

50 Things 13

Date/Time related stuff

  • "constructor" functions

d = date (2011, 6, 7) dt = datetime (2011, 6, 7, 11, 15, 0, 0) dtz = datetime-tz (2011, 6, 7, 11, 15, 0, -240)

slide-14
SLIDE 14

50 Things 14

ABL Calendar

  • Based on Gregorian Calendar
  • Epoch Date

1 January – 4713 at 00:00:00

  • Units

DATE datatype: days DATETIME: milliseconds DATETIME-TZ: milliseconds

slide-15
SLIDE 15

50 Things 15

Different Calendars

  • UNIX time

– epoch is Jan 1, 1970 at 00:00:00 – unit is seconds

  • JMS time

– epoch is Jan 1, 1970 at 00:00:00 – unit is milliseconds

  • Windows time

– epoch is Jan 1, 1601 at 00:00:00 – unit is centinanoseconds (100 nanoseconds) aka "ticks"

slide-16
SLIDE 16

50 Things 16

Useful Time Constants

Number Description 116 444 736 000 000 000 ticks from 1/1/1601 to 1/1/1970 11 644 473 600 000 milliseconds from 1/1/1601 to 1/1/1970 2 305 814 days from 1/1/- 4713 to 1/1/1601 2 440 588 days from 1/1/- 4713 to 1/1/1970 134 774 days from 1/1/1601 to 1/1/1970 210 866 889 600 seconds from 1/1/- 4713 to 1/1/1970 3 600 seconds in 1 hour 86 400 seconds in 1 day 31 536 000 seconds in 365 days

slide-17
SLIDE 17

50 Things 17

Time arithmetic is easy

with datetime and datetime-tz data types arithmetic units is milliseconds def var startTime as datetime. def var endTime as datetime. def var i as int64. i = endTime - startTime. endTime = startTime + i.

slide-18
SLIDE 18

50 Things 18

Arithmetic in other units

def var startTime as datetime. def var endTime as datetime. def var nSecs as int64. def var nDays as int64. nSecs = (endTime – startTime) / 1000. nDays = (endTime – startTime) / 86400000. /* but this is too hard !!! */

slide-19
SLIDE 19

50 Things 19

INTERVAL: A useful function

i = INTERVAL (endTime, startTime, units). startTime, endTime are expressions of type DATE, DATETIME, or DATETIME-TZ units is a character expression evaluating to one of "years", "months", "weeks", "days", "hours", "minutes", "milliseconds"

slide-20
SLIDE 20

50 Things 20

Changing Times

From Windows to DATETIME:

  • 0. convert from ticks to milliseconds
  • 1. adjust for epoch difference

def var wintime as int64 no-undo. def var dt as datetime no-undo. wintime = wintime / 10000. dt = add-interval (datetime (1, 1, 1601, 0, 0, 0, 0), wintime, "milliseconds").

slide-21
SLIDE 21

50 Things 21

Changing Times

From DATETIME-TZ to UNIX: 0) adjust for epoch difference in seconds def var dt as datetime-tz no-undo. def var unixTime as int64 no-undo. unixTime = interval (dt, DATETIME-TZ (1, 1, 1970, 0, 0, 0, 0, 0), "seconds").

slide-22
SLIDE 22

50 Things 22

Time Zones

DATETIME-TZ data type milliseconds from epoch stored as GMT with originating session time zone offset (in minutes) def var tzoffset as int no-undo. tzoffset = timezone (dt-tz expression). gives you the timezone offset dtz = datetime-tz (dtz, tzoffset) to change a timezone offset

slide-23
SLIDE 23

50 Things 23

Time Zones

DATETIME-TZ: database indexing ignores timezone arithmetic ignores timezone comparison operators (>, <, >=, <=, =, <>) ignore timezone

slide-24
SLIDE 24

50 Things 24

Time Zones

SESSION:DISPLAY-TIMEZONE integer timezone offset used for formatting initialized to ? when ? then SESSION:TIMEZONE is used instead.

slide-25
SLIDE 25

50 Things 25

Time Zones

SESSION:TIMEZONE integer session timezone offset initialized to ? set with timezone function: SESSION:TIMEZONE = TIMEZONE.

slide-26
SLIDE 26

50 Things 26

Some other things

slide-27
SLIDE 27

50 Things 27

Import data thruough stdin, stdout

On UNIX and Linux: cat cdata.txt | pro -b -p import.p | cat On Windows: type cdata.txt | pro -b -p import.p | more the program imp.p: def var c as char no-undo. import cv. put unformatted string (c).

slide-28
SLIDE 28

50 Things 28

How many BI clusters exist?

find _AreaStatus where _AreaStatus-Areanum = 3. find _dbStatus display _AreaStatus-Hiwater * _dbStatus._DbStatus-BiBlkSize / _dbStatus-BiClSize / 1024 . Can’t tell how many are active though

slide-29
SLIDE 29

50 Things 29

Excel can load HTML Create an HTML table text file Use one HTML table record per table row One cell per field

To get formatted data into Excel

slide-30
SLIDE 30

50 Things 30

Sample: ¡ <table ¡border=0 ¡cellpadding=0 ¡cellspacing=0 ¡width=1034> ¡ ¡<col ¡width=146> ¡ ¡<col ¡width=185> ¡ ¡<col ¡width=159> ¡ ¡<col ¡width=181> ¡ ¡<tr ¡height=13> ¡ ¡ ¡<td>Marv ¡Stone</td> ¡ ¡ ¡<td>Systems ¡Engineering</td> ¡ ¡ ¡<td>Progress ¡Software</td> ¡ ¡ ¡<td>marv@example.com</td> ¡ ¡</tr> ¡ </table> ¡

slide-31
SLIDE 31

50 Things 31

Sample: ¡ <table ¡border=0 ¡cellpadding=0 ¡cellspacing=0 ¡width=1034> ¡ ¡<col ¡width=146> ¡ ¡<col ¡width=185> ¡ ¡<col ¡width=159> ¡ ¡<col ¡width=181> ¡ ¡<tr ¡height=13> ¡ ¡ ¡<td>Marv ¡Stone</td> ¡ ¡ ¡<td>Systems ¡Engineering</td> ¡ ¡ ¡<td>Progress ¡Software</td> ¡ ¡ ¡<td>marv@example.com</td> ¡ ¡</tr> ¡ </table> ¡

slide-32
SLIDE 32

50 Things 32

for ¡each ¡_AreaStatus ¡where ¡ ¡ ¡ ¡ ¡( ¡not ¡_AreaStatus-­‑Areaname ¡matches ¡"*After ¡Image ¡Area*" ¡) ¡ ¡ ¡ ¡no-­‑lock: ¡ ¡display ¡ ¡ ¡ ¡_AreaStatus-­‑Areanum ¡ ¡format ¡">>>" ¡column-­‑label ¡"Num" ¡ ¡ ¡_AreaStatus-­‑Areaname ¡format ¡"x(20)" ¡column-­‑label ¡"Area ¡Name" ¡ ¡ ¡_AreaStatus-­‑Totblocks ¡column-­‑label ¡"Tot ¡blocks" ¡ ¡ ¡_AreaStatus-­‑Hiwater ¡column-­‑label ¡"High ¡water ¡mark" ¡ ¡ ¡_AreaStatus-­‑Hiwater ¡/ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡_AreaStatus-­‑Totblocks ¡* ¡100 ¡column-­‑label ¡"% ¡use" ¡ ¡ ¡_AreaStatus-­‑Extents ¡ ¡format ¡">>>" ¡column-­‑label ¡"Num ¡Extents" ¡ ¡ ¡_AreaStatus-­‑Freenum ¡column-­‑label ¡"Free ¡num" ¡ ¡ ¡_AreaStatus-­‑Rmnum ¡ ¡ ¡column-­‑label ¡"RM ¡num" ¡ ¡ ¡. ¡

  • end. ¡

How much space is used?

slide-33
SLIDE 33

50 Things 33

find ¡first ¡_MyConnection ¡no-­‑lock. ¡ for ¡each ¡_UserTableStat ¡where ¡ ¡ ¡_UserTableStat-­‑Conn ¡= ¡_MyConnection._MyConn-­‑UserId ¡ ¡ ¡no-­‑lock: ¡ ¡ ¡find ¡_file ¡where ¡_file-­‑num ¡= ¡_UserTableStat-­‑Num ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡no-­‑lock ¡no-­‑error. ¡ ¡ ¡if ¡available ¡_file ¡then ¡ ¡ ¡display ¡ ¡ ¡ ¡ ¡_UserTableStat._UserTableStat-­‑Num ¡ ¡ ¡ ¡ ¡_file-­‑name ¡format ¡"x(20)" ¡ ¡ ¡ ¡ ¡_UserTableStat-­‑read ¡ ¡ ¡format ¡">>>>>>>>>>" ¡ ¡ ¡ ¡ ¡_UserTableStat-­‑create ¡format ¡">>>>>>>>>>" ¡ ¡ ¡ ¡ ¡_UserTableStat-­‑update ¡format ¡">>>>>>>>>>" ¡ ¡ ¡ ¡ ¡_UserTableStat-­‑delete ¡format ¡">>>>>>>>>>". ¡

  • end. ¡

What tables are being used?

slide-34
SLIDE 34

50 Things 34

Table ¡# ¡File-­‑Name ¡ ¡ ¡ ¡ ¡ ¡ ¡read ¡create ¡update ¡delete ¡ ::::::: ¡::::::::::::: ¡:::::: ¡:::::: ¡:::::: ¡:::::: ¡ ¡ ¡ ¡ ¡ ¡ ¡1 ¡Invoice ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡5 ¡ ¡ ¡ ¡ ¡ ¡ ¡2 ¡Customer ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡2 ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡1 ¡ ¡ ¡ ¡ ¡ ¡ ¡3 ¡Item ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡4 ¡Order ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡6 ¡ ¡ ¡ ¡ ¡ ¡ ¡5 ¡Order-­‑Line ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡21 ¡ ¡ ¡ ¡ ¡ ¡ ¡6 ¡Salesrep ¡ ¡ ¡ ¡ ¡ ¡ ¡7 ¡State ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡52 ¡ ¡ ¡ ¡ ¡ ¡ ¡8 ¡Local-­‑Default ¡ ¡ ¡ ¡ ¡ ¡ ¡9 ¡Ref-­‑Call ¡

slide-35
SLIDE 35

50 Things 35

Same ¡technique ¡as ¡for ¡tables, ¡but ¡read ¡ the ¡data ¡from ¡the ¡_UserIndexStat ¡table ¡

What indexes are being used?

slide-36
SLIDE 36

50 Things 36

for ¡each ¡_StorageObject ¡no-­‑lock ¡ ¡ ¡ ¡where ¡_StorageObject._Object-­‑type ¡= ¡1 ¡and ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡_StorageObject._Area-­‑number ¡> ¡6 ¡ ¡ ¡find ¡_Area ¡ ¡ ¡ ¡ ¡where ¡_Area._Area-­‑number ¡= ¡_StorageObject._Area-­‑number ¡ ¡ ¡ ¡ ¡ ¡no-­‑lock ¡no-­‑error. ¡ ¡ ¡find ¡_File ¡ ¡ ¡ ¡ ¡where ¡_File._File-­‑number ¡= ¡_StorageObject._Object-­‑number ¡ ¡ ¡ ¡ ¡no-­‑lock ¡no-­‑error. ¡ ¡ ¡display ¡ ¡ ¡ ¡ ¡_StorageObject._Area-­‑number ¡format ¡">>9” ¡ ¡ ¡ ¡ ¡ ¡ ¡column-­‑label ¡"Area" ¡ ¡ ¡ ¡ ¡_Area._Area-­‑name ¡format ¡"x(30)" ¡column-­‑label ¡"Name" ¡ ¡ ¡ ¡ ¡_File._File-­‑nam ¡when ¡available ¡_File ¡ ¡column-­‑label ¡"Table". ¡

  • end. ¡

Which areas are tables in?

slide-37
SLIDE 37

50 Things 37

List tables by storage area

for each _Area, each _Storageobject where (_Storageobject._Area-number = _Area._Area-number), each _File where (_File._File-Number = _Storageobject._Object-number) and (_File._File-Number > 0) break by _File._File-name: display _Area._Area-name _File._File-name. end.

slide-38
SLIDE 38

50 Things 38

Listing of tables by storage area

Area-name File-Name Schema Area agedar Schema Area agedar Schema Area customer Schema Area customer Schema Area item Schema Area item Schema Area monthly Schema Area monthly

slide-39
SLIDE 39

50 Things 39

List tables by storage area

for each _Area, each _Storageobject where (_Storageobject._Area-number = _Area._Area-number), each _File where (_File._File-Number = _Storageobject._Object-number) and (_File._File-Number > 0) break by _File._File-name: display _Area._Area-name _File._File-name. end.

slide-40
SLIDE 40

50 Things 40

List tables by storage area 2

for each _Area, each _Storageobject where (_Storageobject._Area-number = _Area._Area-number), each _File where (_File._File-Number = _Storageobject._Object-number) and (_File._File-Number > 0) and (_StorageObject._Object-type eq 1) break by _File._File-name: display _Area._Area-name _File._File-name. end.

slide-41
SLIDE 41

50 Things 41

List indexes by storage area and table

for each _Area, each _Storageobject where (_Storageobject._Area-number = _Area._Area-number and (_StorageObject._Object-type eq 2) , each _Index where (_Index._Idx-num = _Storageobject._Object-number): find _File of _Index. if (_File._File-number > 0) then display _Area._Area-name _File._File-name _Index._Index-name. end.

slide-42
SLIDE 42

50 Things 42

List Tables and Their Fields

  • utput to tables.txt.

for each _file where (0 < _file-num): put _file-name skip. for each _field of _file: put “ “ _field-name skip. end. put “” skip. end.

  • utput close.
slide-43
SLIDE 43

50 Things 43

Table and fields

Invoice Adjustment Amount Cust-Num Invoice-Date Invoice-Num Order-Num Ship-Charge Total-Paid Customer Address Address2 Balance City

slide-44
SLIDE 44

50 Things 44

DEF ¡VAR ¡MyVar ¡AS ¡INT. ¡ MyVar ¡= ¡RANDOM(-­‑10,11). ¡ CASE ¡TRUE: ¡ ¡ ¡ ¡WHEN ¡MyVar ¡LE ¡10 ¡AND ¡MyVar ¡GT ¡1 ¡THEN ¡ ¡ ¡ ¡ ¡ ¡ ¡MESSAGE ¡"case1" ¡MyVar ¡VIEW-­‑AS ¡ALERT-­‑BOX. ¡ ¡ ¡ ¡WHEN ¡MyVar ¡LE ¡1 ¡ ¡AND ¡MyVar ¡GT ¡0 ¡THEN ¡ ¡ ¡ ¡ ¡ ¡ ¡MESSAGE ¡"case2" ¡MyVar ¡VIEW-­‑AS ¡ALERT-­‑BOX. ¡ ¡ ¡ ¡WHEN ¡MyVar ¡LE ¡0 ¡THEN ¡ ¡ ¡ ¡ ¡ ¡ ¡MESSAGE ¡"case3" ¡MyVar ¡VIEW-­‑AS ¡ALERT-­‑BOX. ¡ ¡ ¡ ¡OTHERWISE ¡ ¡ ¡ ¡ ¡ ¡ ¡MESSAGE ¡"case4" ¡MyVar ¡VIEW-­‑AS ¡ALERT-­‑BOX. ¡ END ¡CASE. ¡

You can do range checks in CASE statements

slide-45
SLIDE 45

50 Things 45

REPEAT: ¡ ¡ ¡ ¡hQuery:GET-­‑NEXT(). ¡ ¡ ¡ ¡IF ¡hQuery:QUERY-­‑OFF-­‑END ¡THEN ¡LEAVE. ¡ ¡ ¡ ¡hBufferField1 ¡= ¡hBuffer:BUFFER-­‑FIELD('Name'). ¡ ¡ ¡ ¡hBufferField2 ¡= ¡hBuffer:BUFFER-­‑FIELD('CustomerCode'). ¡ ¡ ¡ ¡DISPLAY ¡hBufferField1:BUFFER-­‑VALUE ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡hBufferField2:BUFFER-­‑VALUE. ¡

  • END. ¡

For dynamic query result fields, instead of this:

slide-46
SLIDE 46

50 Things 46

REPEAT: ¡ ¡ ¡ ¡hQuery:GET-­‑NEXT(). ¡ ¡ ¡ ¡IF ¡hQuery:QUERY-­‑OFF-­‑END ¡THEN ¡LEAVE. ¡ ¡ ¡ ¡DISPLAY ¡hBuffer::Name ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡hBuffer::CustomerCode. ¡

  • END. ¡

You can do it this way

slide-47
SLIDE 47

50 Things 47

Instead of adding and deleting MESSAGE statements in your code for debugging purposes, add PUBLISH statements and leave them in there forever: At runtime, you can SUBSCRIBE to this information when you need it, even in production, and decide what you do with it. You can DISPLAY the information in a Window. Write it to a log file (on AppServer or WebSpeed). The overhead is minimal if you don’t subscribe. PUBLISH ¡“message” ¡(PROGRAM-­‑NAME(1), ¡<level>, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡<message>). ¡

Use PUBLISH for debugging

slide-48
SLIDE 48

50 Things 48

You can PUBLISH debug messages from classes using the following syntax: PUBLISH ¡“message” ¡FROM ¡(SESSION:FIRST-­‑PROCEDURE) ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡(PROGRAM-­‑NAME(1), ¡<level>, ¡<message>). ¡ You can process these messages in exactly the same way as from a procedure PROGRAM-NAME(1) returns the name of the class. Make sure there is a SESSION:FIRST-PROCEDURE

PUBLISH from classes:

slide-49
SLIDE 49

50 Things 49

Use smtp server that is built in to Microsoft IIS. It is very simple to use. Does not need usercode/password setup and is very fast. def ¡var ¡chMessage ¡as ¡com-­‑handle ¡no-­‑undo. ¡ create ¡"CDO.Message" ¡chMessage. ¡ chMessage:Subject ¡= ¡"Test ¡Subject". ¡ chMessage:From ¡= ¡"TestFrom@test.com". ¡ chMessage:To ¡= ¡"TestTo@test.com". ¡ chMessage:TextBody ¡= ¡"Test ¡Body". ¡ chMessage:Send(). ¡ release ¡object ¡chMessage. ¡

To send email from WebSpeed

slide-50
SLIDE 50

50 Things 50

Regenerate the .Net assembly with "register for COM Interop" = true in Build settings. That will generate .tlb (Type library). Now you can use that from Progress in the same manner as a .dll. If you don't own the source code to regenerate, you can code a .Net wrapper around dll and expose the wrapper as type library. This is a good way to get functionality in Progress that is readily available in .Net.

Call .Net assemblies from 4GL

slide-51
SLIDE 51

50 Things 51

Are we up to 50 yet ?

slide-52
SLIDE 52

50 Things 52

With your OpenEdge install, there are variety of functions and programs in the $DLC/src/samples folder. Examples includes source code for finding weekday, weeknum, get current folder path, get unique numbers, sample code for activex, .Net, sockets etc. Go read it, you are likely to find something useful. Some of them are good.

slide-53
SLIDE 53

50 Things 53

Questions

email: gus@progress.com