Main Tables Views Materialized Views Indexes Constraints Triggers Procedures Functions Packages Sequences Java Sources Jobs 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: END rpm;

Package body source

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