Professional Documents
Culture Documents
Please take note: these standards are in DRAFT form; you should read and edit them carefully before applying them in your own organization. PL/Solutions does not warrant their accuracy or applicability to your development process.
Table of Contents
Table of Contents..............................................................................................................................................2 Introduction.......................................................................................................................................................3 Benefits of Having Standards .......................................................................................................................3 Format of this Document..............................................................................................................................3 File naming conventions...................................................................................................................................3 Identifier naming conventions..........................................................................................................................4 Scope.............................................................................................................................................................4 Type..............................................................................................................................................................4 Primary Identifier..........................................................................................................................................5 Modifier........................................................................................................................................................5 Suffix............................................................................................................................................................5 Variable Usage Conventions ............................................................................................................................6 Cursor Declarations ....................................................................................................................................6 FOR loop index ............................................................................................................................................6 PL/SQL table TYPE ....................................................................................................................................7 Programmer-defined subtype .......................................................................................................................7 PL/SQL Record TYPE ................................................................................................................................8 Code format......................................................................................................................................................8 Indentation....................................................................................................................................................8 Using Case to Aid Readability.....................................................................................................................9 Formatting Single Statements.......................................................................................................................9 Formatting Declarations .............................................................................................................................10 Formatting Multiline Statements................................................................................................................10 Commenting style...........................................................................................................................................11 Comment As you Code...............................................................................................................................11 Explain Why - Not the How.......................................................................................................................11 Make Comments Easy to Enter and Maintain............................................................................................11 Maintain Indentation...................................................................................................................................11 Syntax Guidelines...........................................................................................................................................11 Branching and Labels................................................................................................................................11 Conditional Statements...............................................................................................................................12 REPETITION.............................................................................................................................................14 Avoid Unstructured Exits from Loops.......................................................................................................18 Do not use PL/SQL where you can use a SQL statement instead. ............................................................18 PL/Sql Programming Guidelines....................................................................................................................18 Use Named Constants to Avoid Hard-coding Values................................................................................18 Convert Variables into Named Constants...................................................................................................19 Avoid the recycling of variables.................................................................................................................19 Name Subtypes to Self-document Code.....................................................................................................19 Remove Unused Variables from Programs................................................................................................20 Use %TYPE when a variable represents a column....................................................................................20 Use %TYPE to standardize non-database declarations..............................................................................20 Use Variables to hide complex logic..........................................................................................................21 Building from high-level rules....................................................................................................................22 Converting pseudo-code to PL/SQL...........................................................................................................23 SQL Guidelines..............................................................................................................................................25 Right align the reserved words...................................................................................................................25 Dont skimp on line seperators...................................................................................................................25 Use sensible abbreviations for table and column aliases............................................................................26
Introduction
The first and most important thing about standards is to have them. Once you sit down and come up with a set of standards then it becomes very easy to follow them. Remember when you first learned to drive! It seemed to take up all your attention just to keep the car going straight ahead. But now you probably do not even think about it. Standards are the same way. Once you get used to them, they dont even seem to exist. The sign of a good standard is that it facilitates your work. Not come in the way of your work. To arrive at that point takes a lot of hard work. That is where PL/Solutions expertise comes in handy. We at PL/Solutions, led by Steven Feuerstein have spent many years culling different approaches to come up with the following standards. Use them and be happy. First and foremost, standards have to be simple. If there are so many rules that you always need a reference card, then you are never going to use them. On the other hand if they are too simple, you might as well not use one. So you need to strike a balance between too hard and too simple to come up with something that is just right for you. Programming is very personal. It is like writing a story or a piece of music, or painting a picture. So we dont pretend that what we are proposing here is the ultimate truth. This has worked for us. We will be happy if it works for you. Having standards is beneficial to a lot of different people.
Easier Maintenance
Maintenance programming becomes easier since the code is easier to read and modify.
Easier to Train
With standard guidelines, it is easy to set up a training program, whether it is a hands on session or a CBT. New hires can be trained in a day or two to conform to the corporate standards.
Easier to Automate
With a well-defined standard you can plug it into an automatic formatter like PL/Formatter from RevealNet and format legacy code to conform to corporate standards.
Examples:
File Type
Stored Package Body
Extension
pkb
Example
dbmsout.pkb
Stored Package Specification Stored Procedure Stored Function Trigger Anonymous block Table creation statement Test script Multiple DDL statements
Scope
Scope is the locality of reference. Knowing this is invaluable to the maintenance programmer. Notice that p is added as the scope of a parameter. This is a good way of denoting that a variable is a parameter to the procedure.
Examples:
Locality g l p Description Global Local Parameter Example g_temp l_temp p_param1
Type
Use the simplest possible types there are. There are only two, constants and variables. You can further breakdown these two into the individual data types, but then it gets complicated. We sure do not want to write complicated code.
Examples:
Type c c c v v v Description Constant Constant Constant Variable Variable Variable Example gc_loop_count lc_loop_count pc_loop_count gv_loop_count lv_loop_count pv_loop_count Comment Global constant Local Constant. Parameter Global Variable Local Variable Parameter
In addition to these scalar types, there are other data types that are supported by the PL/SQL language. They are aggregate data types, which are as follows: Type cur vcr tbl rec Description Cursor Cursor(variable) Table Record Example gcur_employee lvcr_employee gtbl_employee ltrec_address
One more thing to define. There are two special constructs that are available in PL/SQL. They are Type and Subtype. We are going to treat these as datatypes. Type typ stp Description TYPE SUBTYPE Example gtyp_new_account_table lstp_employee_ID
Primary Identifier
Primary identifier is the most important part of a name. This can be a single word or a phrase. We will talk of lengths of names later but it is always a trade off between length for documentation and brevity for typing purposes. We would want to be optimal. This should pretty much tell the reader the purpose of this identifier. Each corporation should have a list of these prime identifiers in the corporate repository. Some examples are account, student, company, phone etc. We will later on discuss some abbreviating rules. A list of abbreviations is also a part of the corporate repository.
Examples
Account, Student, Company, Phone etc.
Modifier
A modifier further qualifies a primary identifier to make it more readable. These modifiers can either precede or succeed a primary identifier. Some examples are for the prime id address, modifier may be mailing forming the name, MailingAddress. Or for Phone it could be, HomePhone etc. A modifier could also be inserted in the middle of a prime id. For example CustomerName can be modified to read CustomerLastName.
Examples:
Primary Identifier address phone customer_name Modifier mailing home last Position Precede Precede Middle Variable mailing_address home_phone customer_last_name
Suffix
The suffix is used to qualify the identifier further to document the usage of the variable. For example, the suffix is used to denote the type of parameter, as in IN, OUT, or INOUT Type i o io Description Input only parameter Output only parameter Both input and output Example pv_num_items_i pv_sum_o pv_sum_io
Now that some basic standards are defined let us look at how some of these standards are used in practice.
Cursor Declarations
Cursors are usually named after the table or a view that is being processed. Use the word cur as the suffix for the variable. You would still specify the scope of the variable as usual. What happens if you pass the cursor in as a parameter? You would end up with two suffixes. Although this is unusual, it works fine. Scope Local Parameter Type cur cur Primary Identifier Account Account Modifier New Old Suffix Null IN Example lcur_new_account pcur_old_account_i
If you have more than one record declared for a single cursor, preface the record name with a word that describes it, such as Scope Local Parameter Global Type rec rec rec Primary Identifier Account Account Account Modifier newest duplicate old Suffix Null IN Example lrec_new_account prec_duplicate_account_i grec_old_account
FOR lv_year_idx IN 1 .. 12
In a cursor loop, the name of the record, which serves, as a loop index should follow the convention described above for records.
PL/SQL table
A PL/SQL table is declared based on a table TYPE statement, as indicated above. In most situations, use the same name as the table type for the table, but leave off the type part of the suffix. The following examples correspond to the previous table types: Scope Local Global Type tbl tbl Primary Identifier Account Account Modifier new old Suffix Example ltbl_new_account gtbl_old_account
Programmer-defined subtype
In PL/SQL Version 2.1 you can define subtypes from base datatypes. Scope Local Global Type stp stp Primary Identifier Primary_key Large_string Modifier Suffix Example lstp_primary_key gstp_large_string
SUBTYPE lstp_primary_key
IS BINARY_INTEGER;
Code format
How you format your code in your source code is an intensely personal issue. Most people use conventions that are imposed by corporate standards. But when there is no standard available then most programmers feel lost. They end up using a mish-mash of techniques that makes the resulting code hard to read. So it is important that every programmer develop a consistent and cohesive coding style that is easy to read and maintain. There are two points of view to formatting. One is the developers view. The other is the maintainers view. A good standard should meet the needs of both views. There is really one fundamental reason for formatting your code: Reveal and reinforce the logical structure of your program. Writing code to please the eye is a waste of time. Code never stays that way for long. What is more important is to show the structure and the intent of the program. We truly believe that the machine should do this for the programmer. So if you follow the rules set forth here, there will be a tool in the future that will magically transform your program into a listing that could be framed as a work of art.
Indentation
Indentation is one of the most common and effective ways to display a programs logical structure. Programs that are indented are lot easier to read than those that are not. Please be aware that indentation is a double edged sword. It is very easy to mislead with inconsistent indentation.
Indentation Recommendations
The following indentation conventions are recommended. Note that the minimum indentation is described. More spaces may be required for the vertical alignment recommended in subsequent guidelines. Use three spaces as the basic unit of indentation for nesting. Use three spaces as the basic unit of indentation for continuation lines.
In our experience 3 or 4 spaces is the ideal way to indent. This amount of spacing not only adequately reveals the logical structure of the code but also keeps the statements close enough together to read comfortably. You also dont run off the edge of the page with deeply nested structures. Although you should try avoiding deeply nested structures, since most human brains cant stack more that 5 items at a time.
Alignment
As mentioned above trying to keep programs pretty is a lot of work. Hence the following recommendations. Do not try to align statements, operators etc. vertically. This not only takes up time, but also leads to realigning text continuously. Indent continuation lines the same three spaces. Provide one declaration per line (at most). Place the first parameter specification on a separate line from the function or procedure declaration. If any of the parameter types are forced beyond the line length limit, place the first parameter specification on a new line indented as for continuation lines. Place one formal parameter specification per line. You may choose to place more than one parameter per line, but always follow the previous rule.
Use white space inside a statement. Always include a space between an identifier and a separator.
lv_var1:=0; lv_var1 := 0 ;
Use spaces to make module calls and their parameter lists more undestandable.
--
Formatting Declarations
Declaration section is used to declare local variables and other structures uses in the PL/SQL block. The following rules are recommended. Place one declaration on each line This follows the same logic that was described previously. Ignore alignment for declarations This again is a personal preference. But keeping declarations aligned is probably more trouble than it is worth. If the program is developed and maintained by a single programmer, may be this has some value. In our experience this declarations do not stay aligned for very long.
(pv_company_id, pv_last_year_date, -- Last comma indicates pv_rollup_type, pv_total) ; -- other parameters to follow.
Commenting style
There are two types of comments. Internal and external. Here we talk about internal comments, which are comments that are part of the program. You can avoid a lot of comments if you write self documenting code. If you apply the guidelines specified in this document, you would avoid writing a lot of comments.
Maintain Indentation
Comments should reinforce indentation and therefore the logical structure of the program. Always starting your comments in the first column disrupts the logical flow of code. Always indent the comments at the same level as the code which they describe.
Syntax Guidelines
Branching and Labels
If you have programmed in Assembler or in an older version of FORTRAN, you are aware that the only form of flow control was using either a Jump or Goto. In early FORTRAN every line was required to be numbered. These numbers were used as labels for branching. Early BASIC also used this numbering scheme. Procedural languages introduced labels that replaced line numbers. There is no need to number each line anymore. PL/SQLs Goto label causes execution to continue from statement where the label is located. Labels are variables with a << prefix and a >> suffix. For example <<start>> is a label.
Nested
IF <condition1> THEN ... ELSE IF <Condition2> THEN ELSE IF <Condition3> THEN ELSE IF <Condition4> THEN END IF; END IF; END IF; END IF; IF <condition1> THEN ELSIF <Condition2> THEN ELSIF <Condition3> THEN ELSIF <Condition4> THEN END IF;
Flat
minutes. You dont want to execute B unless A is TRUE -- and you dont want to rely on the compiler to decide which clause is evaluated first.
ELSIF sal BETWEEN 20000 AND 30000 THEN ... END IF;
IF total_sal BETWEEN 10000 AND 50000 AND emp_status (emp_rec.empno) = 'N' AND (MONTHS_BETWEEN
(emp_rec.hiredate, SYSDATE) > 10) THEN give_raise (emp_rec.empno); END IF; IF eligible_for_raise (emp_rec.empno) THEN give_raise (emp_rec.empno); END IF;
IF hiredate < SYSDATE THEN date_in_past := TRUE; ELSE date_in_past := FALSE; END IF;
With this:
REPETITION
Programming involves performing a task repeatedly, until a particular condition is met. Looping constructs of a language support this need. There are three basic types of looping. 0 or more loops, 1 or more loops, and Loop for a specified number of times. PL/SQL supports all three types.
END LOOP;
Again notice that the indentation is consistent at 3 spaces.
emp_rec emp_cur%ROWTYPE;
Suppose you need the value of the loop index (year_count in the following example) for debugging:
DECLARE
EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE ('Error in year ' || TO_CHAR (year_count)); END;
In this case use a local variable and copy the loop index to local variable:
DECLARE
BEGIN FOR year_count IN 1 .. 20 LOOP my_count := year_count; calc_pnl (year_count); END LOOP;
END;
A FOR loop should only be used when you want to execute the body a fixed number of times. Stay for the duration or use a different loop construct. Do not use the EXIT syntax in a WHILE loop. The loop should be terminated only when the condition in the boundary evaluates to FALSE. Note: if an exception is raised and the loop stops, that is a legitimate early termination.
Do not use PL/SQL where you can use a SQL statement instead.
The SQL statement will often be much faster. You should replace PL/SQL loops with single SQL statements when possible. Slower PL/SQL Version
FOR year_count IN 1 .. 20 LOOP INSERT INTO v1table1 SELECT * FROM v1table2 WHERE yr_nu = year_count; END LOOP;
Faster, Simpler SQL Version
INSERT INTO v1table1 SELECT * FROM v1table2 WHERE yr_nu BETWEEN 1 AND 20;
2. Allow the value of that literal (now a constant) to be set in only one place in your code, preferably with call to a procedure. This procedure can be run on start-up of the application, or from the initialization section of a package. 3. Provide a single way to retrieve the literal value, preferably through a call to a function. Don't let any program reference the literal directly. This way you reserve the right and ability to change at any time the data structures you use to store that literal -- without affecting any of the programs which rely on that constant.
SUBTYPE room_number_type IS POSITIVE; ... -- A declaration using the subtype: open_room room_number_type;
customer.cust_city%TYPE;
state customer.cust_state_abbrev_cd%TYPE; soc_sec# BEGIN ... interact with database customer information ... END;
Using the %TYPE attribute ensures that your variables stay synchronized with your database structure. Just as importantly, though, this declaration section is more self documenting now. The %TYPE attribute provides important information to anyone reviewing the code, stating: "These variables represent my columns in the program. When you see one of these variables, think 'database column'." This correlation makes it easier to understand the code, easier to change the code, and easier to recognize when one of those variables is used in an inappropriate manner.
customer.cust_soc_sec_number%TYPE;
columns. Use the %TYPE attribute to infer a variable's datatype from another, previously defined PL/SQL variable. The following declarations use this alternative source:
DECLARE revenue_data NUMBER(20,2); total_revenue revenue_data%TYPE; -max_available_date DATE := LAST_DAY (ADD_MONTHS (SYSDATE, 3)); last_ship_date max_available_date%TYPE;
The variable called revenue_data acts as the standard variable for revenue data. Whenever we declare the total_revenue variable (or any other revenue-related variables), we can base it on the general revenue_data variable. By doing this, we guarantee a consistent declaration of revenue variables. Furthermore, if the revenue datatypes ever need to be changed again, we only have to change the way that revenue_data is declared and recompile. All variables declared with revenue_data%TYPE will automatically adjust. Note that while max_available_date has a default value as well, it is not applied to last_ship_date. Everything up to the optional default value assignment (initiated with a DEFAULT keyword or assignment operator) in a declaration is used in the %TYPE declaration, such as NOT NULL and the datatype. The default value, if specified in the source variable declaration, is ignored. To make it easiest for individual developers to be aware of and make use of standard variable declarations, consider creating a package that contains only standard variable declarations and any code necessary to initialize them, as follows:
/* Source for any Y/N flagswhen you don't use Booleans */ flag_data CHAR(1);
END std_vartypes;
A variable is a chunk of memory that has a name. A variable can hold a simple value. It can also be assigned the value of the outcome of an arbitrarily complicated expressioneither through a default value setting or an assignment. In this way a variable can "represent" that complex expression and thus be used in place of that expression in your code. The result is a program which is easy to read and maintain. Consider the following code fragment:
IF (shipdate < ADD_MONTHS (SYSDATE, +3) OR order_date >= ADD_MONTHS (SYSDATE, -2)) AND cust_priority_type = 'HIGH' AND order_status = 'O' THEN ship_order ('EXPRESS');
ELSIF (order_date >= ADD_MONTHS (SYSDATE, -2) OR ADD_MONTHS (SYSDATE, 3) > shipdate) AND order_status = 'O' THEN ship_order ('GROUND'); END IF;
If you skip past the complicated Boolean expressions and look at the code executed in each IF and ELSIF clause you can "reverse-engineer" the understanding of the code. It looks like the IF statement is used to determine the method by which an order should be shipped. Unfortunately, it would be very difficult to discern this fact from the conditions in the IF statement. Those Boolean expressions with multiple components are, in and of themselves, almost impossible to interpret without drawing a diagram. If there is an error in this logic, no one but the original author would be able to readily untangle the knot.
IF order-overdue THEN
Some naming and coding standards for PL/SQL DRAFT Page 22
IF customer-priority-is-high THEN ship-express; ELSE ship-ground; END IF; ELSE ship-ground; END IF;
The next step would be to rewrite this nested IF statement as follows:
BEGIN IF order_overdue AND high_priority THEN ship_order ('EXPRESS'); ELSE ship_order ('GROUND'); END IF; END;
We don't know how ship_order will behave and, again, at this moment we dont care. We'll employ top-down design to "fill in the blanks" and then work out the details later.
DECLARE /* I hide my business rule behind this variable. */ order_overdue CONSTANT BOOLEAN DEFAULT (shipdate < ADD_MONTHS (SYSDATE, +3) OR order_date >= ADD_MONTHS (SYSDATE, -2)) AND order_status = 'O';
BEGIN IF order_overdue AND high_priority THEN ship_order ('EXPRESS'); ELSE ship_order ('GROUND'); END IF; END;
In this final version of the IF statement, weve used the order_overdue constant to abstract out or hide the two-part check against the order and ship dates. Now the IF-THEN code is much easier to read; in fact, it all but explains itself through the names of the constants. This self-documenting capability reduces the need for separate comments in the code. By consolidating the redundant code, it also makes it easier to maintain the application. If the conditions which make an order "overdue" change, we do not need to hunt through the code for all the
places which perform the order_overdue test. We need only change the default value given to the order_overdue constant. This approach can be taken a step further by placing the business rule logic into a Boolean function. We can then call this function from any of our programs and avoid reproducing the logic in that declaration statement.
SQL Guidelines
Right align the reserved words Select
SELECT last_name, first_name FROM employee WHERE department_id = 15 AND hire_date < SYSDATE;
Insert
INSERT INTO employee (employee_id, ) VALUES (105, );
Update
UPDATE employee SET hire_date = SYSDATE WHERE hire_date IS NULL AND termination_date IS NULL
Delete
DELETE FROM employee WHERE department_id = 15;
FROM employee E Company C Salary_history SH WHERE E.company_id = C.company_id AND E.employee_id = SH.employee_id AND E.hire_date > ADD_MONTHS (SYSDATE, -60); UPDATE employee SET hire_date = SYSDATE Termination_date = NULL WHERE department_id = 105;
SELECT
select list
FROM employee A Company B History C Bonus D Profile E Sales F WHERE A.company_id = B.company_id AND A.employee_id = C.employee_id AND B.company_id = F.company_id AND A.employee_id = D.employee_id AND B.company_id = E.company_id;
Use a code segment such as,
SELECT
select list
FROM employee EMP Company CO History HIST Bonus Profile PROF Sales WHERE EMP.company_id = CO.company_id AND EMP.employee_id = HIST.employee_id