Main Tables Views Materialized Views Indexes Constraints Triggers Procedures Functions Packages Sequences Java Sources Sanity Check Index DDL scrips
Package source Package body source

RPM

DDL script

Package source

Legend: comment string keyword reserved word operator
     1: PACKAGE rpm AS
     2:     FUNCTION vercmp(
     3:         e1 VARCHAR2, v1 VARCHAR2, r1 VARCHAR2,
     4:         e2 VARCHAR2, v2 VARCHAR2, r2 VARCHAR2)
     5:     RETURN NUMBER
     6:         DETERMINISTIC
     7:         PARALLEL_ENABLE;
     8:     PRAGMA RESTRICT_REFERENCES(vercmp, WNDS, RNDS);
     9: 
    10:     FUNCTION vercmpCounter
    11:     return NUMBER
    12:         PARALLEL_ENABLE;
    13:     PRAGMA RESTRICT_REFERENCES(vercmpCounter, WNDS, RNDS);
    14: 
    15:     FUNCTION vercmpResetCounter
    16:     return NUMBER
    17:         PARALLEL_ENABLE;
    18:     PRAGMA RESTRICT_REFERENCES(vercmpResetCounter, WNDS, RNDS);
    19: 
    20: END rpm;

Package body source

Legend: comment string keyword reserved word operator
     1: PACKAGE BODY rpm AS
     2:     vercmp_counter NUMBER := 0;
     3: 
     4:     FUNCTION isdigit(ch CHAR)
     5:     RETURN BOOLEAN
     6:     deterministic
     7:     IS
     8:     BEGIN
     9:         if ascii(ch) between ascii('0') and ascii('9')
    10:         then
    11:             return TRUE;
    12:         end if;
    13:         return FALSE;
    14:     END isdigit;
    15: 
    16: 
    17:     FUNCTION isalpha(ch CHAR)
    18:     RETURN BOOLEAN
    19:     deterministic
    20:     IS
    21:     BEGIN
    22:         if ascii(ch) between ascii('a') and ascii('z') or
    23:             ascii(ch) between ascii('A') and ascii('Z')
    24:         then
    25:             return TRUE;
    26:         end if;
    27:         return FALSE;
    28:     END isalpha;
    29: 
    30: 
    31:     FUNCTION isalphanum(ch CHAR)
    32:     RETURN BOOLEAN
    33:     deterministic
    34:     IS
    35:     BEGIN
    36:         if ascii(ch) between ascii('a') and ascii('z') or
    37:             ascii(ch) between ascii('A') and ascii('Z') or
    38:             ascii(ch) between ascii('0') and ascii('9')
    39:         then
    40:             return TRUE;
    41:         end if;
    42:         return FALSE;
    43:     END isalphanum;
    44: 
    45: 
    46:     FUNCTION rpmstrcmp (string1 IN VARCHAR2, string2 IN VARCHAR2)
    47:     RETURN NUMBER
    48:     deterministic
    49:     IS
    50:         digits CHAR(10) := '0123456789';
    51:         lc_alpha CHAR(27) := 'abcdefghijklmnopqrstuvwxyz';
    52:         uc_alpha CHAR(27) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    53:         alpha CHAR(54) := lc_alpha || uc_alpha;
    54:         str1 VARCHAR2(32767) := string1;
    55:         str2 VARCHAR2(32767) := string2;
    56:         one VARCHAR2(32767);
    57:         two VARCHAR2(32767);
    58:         isnum BOOLEAN;
    59:     BEGIN
    60:         if str1 is NULL or str2 is NULL
    61:         then
    62:             raise VALUE_ERROR;
    63:         end if;
    64:         -- easy comparison to see if versions are identical
    65:         if str1 = str2
    66:         then
    67:             return 0;
    68:         end if;
    69:         -- loop through each version segment of str1 and str2 and compare them
    70:         one := str1;
    71:         two := str2;
    72: 
    73:         <<segment_loop>>
    74:         while one is not null and two is not null
    75:         loop
    76:             declare
    77:                 segm1 VARCHAR2(32767);
    78:                 segm2 VARCHAR2(32767);
    79:             begin
    80:                 --DBMS_OUTPUT.PUT_LINE('Params: ' || one || ',' || two);
    81:                 -- Throw out all non-alphanum characters
    82:                 while one is not null and not isalphanum(one)
    83:                 loop
    84:                     one := substr(one, 2);
    85:                 end loop;
    86:                 while two is not null and not isalphanum(two)
    87:                 loop
    88:                     two := substr(two, 2);
    89:                 end loop;
    90:                 --DBMS_OUTPUT.PUT_LINE('new params: ' || one || ',' || two);
    91: 
    92:                 str1 := one;
    93:                 str2 := two;
    94: 
    95:                 /* grab first completely alpha or completely numeric segment */
    96:                 /* leave one and two pointing to the start of the alpha or numeric */
    97:                 /* segment and walk str1 and str2 to end of segment */
    98: 
    99:                 if str1 is not null and isdigit(str1)
   100:                 then
   101:                     str1 := ltrim(str1, digits);
   102:                     str2 := ltrim(str2, digits);
   103:                     isnum := true;
   104:                 else
   105:                     str1 := ltrim(str1, alpha);
   106:                     str2 := ltrim(str2, alpha);
   107:                     isnum := false;
   108:                 end if;
   109: 
   110:                 --DBMS_OUTPUT.PUT_LINE('Len: ' || length(str1) || ',' || length(str2));
   111:                 -- Oracle trats the length of an empty string as null
   112:                 if str1 is not null
   113:                 then segm1 := substr(one, 1, length(one) - length(str1));
   114:                 else segm1 := one;
   115:                 end if;
   116: 
   117:                 if str2 is not null
   118:                 then segm2 := substr(two, 1, length(two) - length(str2));
   119:                 else segm2 := two;
   120:                 end if;
   121: 
   122:                 --DBMS_OUTPUT.PUT_LINE('Segments: ' || segm1 || ',' || segm2);
   123:                 --DBMS_OUTPUT.PUT_LINE('Rest: ' || str1 || ',' || str2);
   124:                 /* take care of the case where the two version segments are */
   125:                 /* different types: one numeric and one alpha */
   126:                 if segm1 is null then return -1; end if; /* arbitrary */
   127:                 if segm2 is null then
   128: 					if isnum then
   129: 						return 1;
   130: 					else
   131: 						return -1;
   132: 					end if;
   133: 				end if;
   134: 
   135:                 if isnum
   136:                 then
   137:                     /* this used to be done by converting the digit segments */
   138:                     /* to ints using atoi() - it's changed because long */
   139:                     /* digit segments can overflow an int - this should fix that. */
   140: 
   141:                     /* throw away any leading zeros - it's a number, right? */
   142:                     segm1 := ltrim(segm1, '0');
   143:                     segm2 := ltrim(segm2, '0');
   144: 
   145:                     /* whichever number has more digits wins */
   146:                     -- length of empty string is null
   147:                     if segm1 is null and segm2 is not null
   148:                     then
   149:                         return -1;
   150:                     end if;
   151:                     if segm1 is not null and segm2 is null
   152:                     then
   153:                         return 1;
   154:                     end if;
   155:                     if length(segm1) > length(segm2) then return 1; end if;
   156:                     if length(segm2) > length(segm1) then return -1; end if;
   157:                 end if;
   158: 
   159:                 /* strcmp will return which one is greater - even if the two */
   160:                 /* segments are alpha or if they are numeric.  don't return  */
   161:                 /* if they are equal because there might be more segments to */
   162:                 /* compare */
   163: 
   164:                 if segm1 < segm2 then return -1; end if;
   165:                 if segm1 > segm2 then return 1; end if;
   166: 
   167:                 one := str1;
   168:                 two := str2;
   169:             end;
   170:         end loop segment_loop;
   171:         /* this catches the case where all numeric and alpha segments have */
   172:         /* compared identically but the segment sepparating characters were */
   173:         /* different */
   174:         if one is null and two is null then return 0; end if;
   175: 
   176:         /* whichever version still has characters left over wins */
   177:         if one is null then return -1; end if;
   178:         return 1;
   179:     END rpmstrcmp;
   180: 
   181: 
   182:     FUNCTION vercmp(
   183:         e1 VARCHAR2, v1 VARCHAR2, r1 VARCHAR2,
   184:         e2 VARCHAR2, v2 VARCHAR2, r2 VARCHAR2)
   185:     RETURN NUMBER
   186:     IS
   187:         rc NUMBER;
   188:     BEGIN
   189:         DECLARE
   190:           ep1 NUMBER;
   191:           ep2 NUMBER;
   192:           BEGIN
   193:             vercmp_counter := vercmp_counter + 1;
   194:             if e1 is null then
   195:               ep1 := 0;
   196:             else
   197:               ep1 := TO_NUMBER(e1);
   198:             end if;
   199:             if e2 is null then
   200:               ep2 := 0;
   201:             else
   202:               ep2 := TO_NUMBER(e2);
   203:             end if;
   204:             -- Epochs are non-null; compare them
   205:             if ep1 < ep2 then return -1; end if;
   206:             if ep1 > ep2 then return 1; end if;
   207:             rc := rpmstrcmp(v1, v2);
   208:             if rc != 0 then return rc; end if;
   209:            return rpmstrcmp(r1, r2);
   210:          END;
   211: 
   212:     END vercmp;
   213: 
   214:     FUNCTION vercmpCounter
   215:     RETURN NUMBER
   216:     IS
   217:     BEGIN
   218:         return vercmp_counter;
   219:     END vercmpCounter;
   220: 
   221:     FUNCTION vercmpResetCounter
   222:     RETURN NUMBER
   223:     IS
   224:         result NUMBER;
   225:     BEGIN
   226:         result := vercmp_counter;
   227:         vercmp_counter := 0;
   228:         return result;
   229:     END vercmpResetCounter;
   230: END rpm;