The result would besomething like the following: Create Procedure prInsertLeasedAsset_2 -- Insert leased asset and update total in LeaseSchedule.. A more elegant solution is to group cod
Trang 1one additional parameter with the default set to 0 to the stored
procedure
@debug int = 0
In the stored procedure, at all important points, I add code that
tests the value of the@debugvariable and displays the values of
selected variables or resultsets:
select * from #Properties
I do not use thePrintstatement for this purpose because
▼ It does not support the display of resultsets
■ In older versions, it was impossible to concatenate a string
inside aPrintstatement
▲ Some utilities handle messages from thePrintstatement
differently than they do the resultset from theSelect
statement
In the following example, you can see a stored procedure that is
designed to support this kind of testing:
Alter Procedure prGetInventoryProperties_2
Return comma-delimited list of properties
which are describing asset.
i.e.: Property=Value unit;Property=Value unit; (
Trang 2Create table #Properties(Id int identity(1,1),
Property varchar(50), Value varchar(50), Unit varchar(50))
identify Properties associated with asset insert into #Properties (Property, Value, Unit) select Property, Value, Unit
from InventoryProperty inner join Property
on InventoryProperty.PropertyId = Property.PropertyId where InventoryProperty.InventoryId = @intInventoryId
if @debug <> 0 select * from #Properties
set loop select @intCountProperties = Count(*),
@intCounter = 1,
Trang 3@chvProperties = ''
from #Properties
loop through list of properties
while @intCounter <= @intCountProperties
begin
get one property
select @chvProperty = Property,
@chvValue = Value,
@chvUnit = Coalesce(Unit, '') from #Properties
check will new string fit
select @insLenProperty = DATALENGTH(@chvProperty),
Trang 4+ '=' + @chvValue + ' ' + @chvUnit + '; '
if @debug <> 0 select @chvProperties chvProperties
let's go another round and get another property set @intCounter = @intCounter + 1
end
drop table #Properties
if @debug <> 0 select '**** '+ @chvProcedure + 'END ****'
return 0
Execution in a Test Environment To debug or test a stored procedure, Iexecute the stored procedure from Query Analyzer with the@debugparameter set to 1
declare @chvResult varchar(8000) exec prGetInventoryProperties
Execution in the Production Environment In production, the storedprocedure is called without a reference to the@debugparameter.Here, SQL Server assigns a default value to the parameter (0), andthe stored procedure is executed without debug statements
exec prGetInventoryProperties
@intInventoryId = 5,
@chvProperties = @chvResult OUTPUT
Trang 5Nested Stored Procedures Two tricks can help you debug a set of
nested stored procedures (that is, when a stored procedure calls
another stored procedure) It is a useful practice to display the
name of the stored procedure at the beginning and end of the
stored procedure
declare @chvProcedure sysname
set @chvProcedure = 'prGetInventoryProperties_2'
Trang 6When you call a nested stored procedure, you need to pass thevalue of the@debugparameter to it as well In this way, you will beable to see its debugging information.
exec prGetInventoryProperties @intInventoryId,
Many errors are a result of the inadequate treatment ofNULLvalues
in Transact-SQL code Developers often forget that local variables ortable columns might containNULLs If such a value becomes part ofany expression, the result will also beNULL
The proper way to test the value of an expression forNULLsis touse theIS NULLorIS NOT NULLclauses Microsoft SQL Server treats
Trang 7the use of= NULLas another way to typeIS NULL, but<> NULLis
not the equivalent ofIS NOT NULL The result of such an expression
is always simplyNULL It will never be true, and stored procedures
will always skip statements after theIfstatement when you use
the<> NULLclause
Assignment of Variable from Resultset
Earlier, we discussed assigning the value(s) for a variable(s) using
the resultset of theSelectstatement This technique is fine when the
resultset returns precisely one record However, if the resultset returns
more than one record, the variable(s) are assigned using the value(s)
from the last record in recordset Not perfect, but in some cases, you
can live with it It is sometimes difficult to predict which record will be
returned as last in the recordset It depends on the query and the index
that SQL Server has used
A more serious problem occurs when the recordset is empty
The values of the variables are changed in this case, and the code is
vulnerable to several mistakes If you do not expect the resultset to be
empty, your stored procedure will fail If you expect the values of the
variables to beNULL, your stored procedure will function correctly
only immediately after it is started (that is, in the first iteration of the
process) In such a case, the local variables are not yet initialized
and will containNULLs Later, when variables are initialized, their
values will remain unchanged If you are testing the contents of the
variables forNULLs to find out if the record was selected, you will
just process the previous record again
Trang 8No Records Affected
Developers sometimes assume that SQL Server will return errors if aTransact-SQL statement affects no records Unfortunately, this error
is semantic rather than syntactic and SQL Server will not detect it
In order to determine such an error, use the@@rowcountfunction rather than the@@errorfunction:
declare @intRowCount int declare @intErrorCode int
update Inventory Set StatusId = -3 where AssetId = -11
select @intRowCount = @@rowCount,
@intErrorCode = @@Error
if @@rowCount = 0 begin
select "Record was not updated!"
return 50001 end
Wrong Size or Datatype
I can recall one occasion when a colleague of mine spent two daysgoing through a complicated data conversion process to find outwhy his process was consistently failing In one of the nested storedprocedures, I had declared the variable astinyintinstead ofint During the testing phase of the project, everything workedperfectly, because the variable was never set to a value higherthan 255 However, a couple of months later in production, theprocess started to fail as values climbed higher
Similar problems can occur if you do not fully understandthe differences between similar formats (for example,charandvarchar,moneyandsmallmoney), or if you fail to synchronize
Trang 9the sizes of datatypes (for instance,char,varchar,numeric, and
other datatypes of variable size)
Default Length
A similar problem can occur when a developer does not supply
the length of the variable datatype and SQL Server assigns a
default length
For example, the default length of thevarchardatatype is 30
Most of the time SQL Server reports an error if the length is omitted,
but not in all cases In theConvertfunction, for example, the user
need only specify the datatype:
Convert(varchar, @intPropertyId)
If the resulting string is short enough, you will not have any
problems I recall a colleague who employed this method for years
without any problems, and then…
Unfortunately, other statements and functions behave as
expected If you declare a variable and assign it like so:
Declare @test varchar
Set @test = '123456789012345678901234567890'
Select datalength(@test), @test
SQL Server will allocate just one byte to the string and return the
In different versions of SQL Server, triggers react differently in rollback
transaction statements When a trigger is rolled back in SQL Server 7.0
or SQL Server 2000, the complete batch that initiated the trigger fails
and the execution continues from the first statement of the next batch
Trang 10Version 4.2 behaves in a similar manner In version 6.0, processingcontinues in the trigger, but the batch is canceled In version 6.5, theprocessing continues in both the trigger and the batch It was theresponsibility of the developer to detect errors and cascade out ofthe process.
Warnings and Lower Priority Errors
Warnings do not stop the execution of a stored procedure In fact,you cannot even detect them from within the SQL Server
environment
Low-level errors, which are detectable using the@@errorfunction, do not abort the execution either Unfortunately, thereare also errors that abort processing completely, so that the errorhandlers in stored procedures do not process the error
/************************************************************
** select *
** from #Properties
*************************************************************/
Deferred Name Resolution
It is possible (in Microsoft SQL Server 7.0 and Microsoft SQLServer 2000) to create database objects (such as stored proceduresand triggers) that refer to other database objects that do not existwithin the database In previous versions, such attempts were treated
as syntax errors This feature helps tremendously when you need togenerate a database structure and objects using script Unfortunately,that introduces a number of risks If you make a typo in the name
Trang 11of the table from which you want to retrieve records, SQL Server
will not report a syntax error during compilation but will report a
runtime error during execution
Create Procedure prDeferredNameResolution
As
set nocount on
select 'Start'
select * from NonExistingTable
select 'Will execution be stopped?'
Server: Msg 208, Level 16, State 1,
Procedure prDeferredNameResolution, Line 7
Invalid object name 'NonExistingTable'.
The execution will be stopped Even an error handler written in
Transact-SQL will not be able to proceed at this point
Cursors
Be very cautious when you use cursors Test the status after each
fetch; place error handling after each command; do not forget to
close and deallocate the cursor when you do not need it any more
There are many rules and regulations for using cursors, and some of
them might seem trivial, but even the smallest mistake can halt the
execution of your code
Overconfidence
The overconfidence that comes with routine may be your worst
enemy If you perform the same or similar tasks over and over
again, you can lose focus and skip basic steps Do not put code into
production before it is thoroughly tested; do not place bug fixes
Trang 12directly into production; use error handling even if the code seemsstraightforward and the chance for error slight.
ERROR HANDLING
A developer’s effective use of error handling procedures isoften an excellent indicator of his or her seniority in that particularprogramming language Those of us who deal with a C or VisualBasic environment are accustomed to a whole set of feature-rich errorhandling objects, procedures, and functions Compared with them,TSQL seems rather inadequate The developer can employ only oneglobal variable and a few procedures for setting or raising errors.However, the apparent inadequacy of the tool set cannot justifysloppy solutions
In this section, we will discuss the concept of error handling andoffer a coherent methodology for its implementation We will alsodiscuss some alternative techniques involving theXACT_ABORTandRaiserrorstatements
Using Error Handling
Since TSQL is so laconic (critics may say feature poor), developmentDBAs commonly express themselves in a very concise manner DBAsfrequently write ad hoc scripts for one-time use or manual execution,and they thus neglect the need for consistent error handling
Logic that is fine in standard languages like Visual Basic or Cfrequently does not work in TSQL For example, an error may occur
in TSQL, but if TSQL does not consider it fatal, processing willcontinue Also, if the error is fatal, all processing will stop Theprocess does not react: it is just killed
Why Bother?
For many, the question is why be concerned with implementingerror handling at all? Let us review this question through thefollowing example:
Trang 13Create Procedure prInsertLeasedAsset_1
Insert leased asset and update total in LeaseSchedule.
(demonstration of imperfect solution)
Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease
where LeaseId = @intLeaseId
commit transaction
return
Trang 14This may seem a trivial example, and it is true that in allprobability nothing would go wrong, but let’s imagine an erroroccurs on theUpdatestatement The error could be for anyreason—overflow, some constraint, or inadequate permission, forexample As explained earlier, transactions do not roll back on theirown when an error occurs Instead, SQL Server simply commitseverything that was changed when it encounters theCommitTransactionstatement as if nothing unusual had happened.Unfortunately, from that moment on, the total of the lease schedulewill have the wrong value.
Tactics of Error Handling
Some DBAs recognize the importance of this issue and place errorhandling in critical positions in their code The result would besomething like the following:
Create Procedure prInsertLeasedAsset_2 Insert leased asset and update total in LeaseSchedule (demonstration of not exactly perfect solution)
As set nocount on
begin transaction
insert asset insert Inventory(EquipmentId, LocationId,
StatusId, LeaseId, LeaseScheduleId, OwnerId,
Trang 15Lease, AcquisitionTypeID) values ( @intEquipmentId, @intLocationId,
Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease
where LeaseId = @intLeaseId
This kind of solution contains substantial repetition—especially if
your business logic requires more than two Transact-SQL statements
to be implemented A more elegant solution is to group codes into a
generic error handling procedure:
Create Procedure prInsertLeasedAsset_3
Insert leased asset and update total in LeaseSchedule.
(demonstration of not exactly perfect solution)
(
@intEquipmentId int,
@intLocationId int,
Trang 16As set nocount on
begin transaction
insert asset insert Inventory(EquipmentId, LocationId,
StatusId, LeaseId, LeaseScheduleId, OwnerId, Lease, AcquisitionTypeID) values ( @intEquipmentId, @intLocationId,
If @@error <> 0 GOTO ERR_HANDLER
Trang 17This is better, but it does not deal with all of the issues that need to
be handled
A typical error that beginners in TSQL make is to check the
value of a global variable and then try to return or process it Such an
attempt is usually the result of a good intention such as wanting to
notify the user of an error that has occurred
Create Procedure prInsertLeasedAsset_4
Insert leased asset and update total in LeaseSchedule.
(demonstration of not exactly perfect solution)
Trang 18update LeaseSchedule Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease where LeaseId = @intLeaseId
If @@Error <> 0 GOTO ERR_HANDLER
commit transaction
return 0
ERR_HANDLER:
Print 'Unexpected error occurred: '
+ Convert(varchar, @@Error) –- this will
not work, as expected Rollback transaction
Return @@ErrorAlthough something like this could work in Visual Basic, forexample, in this case the stored procedure will return 0 as an errornumber SQL Server sets the value of the@@Errorvariable after eachstatement It treats each statement separately, so the
value of@@Erroris set to 0 subsequently when theIfstatement is(successfully) executed Thus thePrintstatement displays 0 as anerror number, and eventually the stored procedure will also return 0
A Coherent Error Handling Methodology
Let’s discuss a single coherent error handling methodology
The fundamental idea is that all SQL statements within a stored
procedure should be covered by this error handling solution Anytime an unexpected error occurs, a stored procedure should stopfurther processing When the current stored procedure stopsprocessing, so should the stored procedures that called it
The basic feature of this solution is to follow all SQL statementswith a statement that reads the contents of the@@Errorvariable,along with anIfstatement, which checks whether the previouscommand completed successfully
Trang 19Create Procedure prInsertLeasedAsset_5
Insert leased asset and update total in LeaseSchedule.
Declare @intErrorCode int
Select @intErrorCode = @@Error
@intStatusId, @intLeaseId,
@intLeaseScheduleId,@intOwnerId,
@mnyLease, @intAcquisitionTypeID) Select @intErrorCode = @@Error
end
If @intErrorCode = 0
begin
— update total
Trang 20update LeaseSchedule Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease where LeaseId = @intLeaseId
Select @intErrorCode = @@Error end
If @intErrorCode = 0 COMMIT TRANSACTION Else
ROLLBACK TRANSACTION
return @intErrorCode
If an error occurs, theIfstatements prevent further execution
of the business logic and pass an error to the end of the procedure.Changes will be rolled back, and the stored procedure returnsthe value of the@intErrorCodevariable to the calling storedprocedure or script If an error occurs, this variable may be used
to notify the calling procedure that there was a problem
Nested Stored Procedures
The calling stored procedure might have the same error handlingsystem in place In such a case, calls to the stored procedures shouldtreat the returned values as error codes:
If @ErrorCode = 0 Begin
execute @intErrorCode = MyStoredProcedure @parm1, @param2… End
The method works like a cascade that stops all further processing in awhole set of nested stored procedures
Interfacing to Other Environments
This error handling structure is very useful even in cases when astored procedure is called from another programming environment,such as Visual Basic or Visual C++ The return value of a stored
Trang 21procedure can be retrieved, and an error can be handled on that
level as well
conn.Open "provider=sqloledb;data source=sqlserver;" + _
"user id=sa;password=;initial catalog=Asset"
Other Global Variables
Cases should be handled with the sameSelectstatement that
reads@@Errorwhen you wish to read the value of some other
global variables immediately after the statement You often
require such a technique when you are using identity columns
insert Inventory(EquipmentId, LocationId,
StatusId, LeaseId, LeaseScheduleId, OwnerId,
Trang 22Lease, AcquisitionTypeID) values ( @intEquipmentId, @intLocationId,
@intStatusId, @intLeaseId,
@intLeaseScheduleId,@intOwnerId,
@mnyLease, @intAcquisitionTypeID) Select @intErrorCode = @@Error,
@intInventoryId = @@identity
Transaction Processing
You can integrate transaction processing perfectly with this solution.Review Chapter 5 to remind yourself whyRollbackandCommitmust be treated differently
At the beginning of a stored procedure or transaction, thedeveloper should add the following code:
Declare @intTransactionCountOnEntry int
If @intErrorCode = 0 Begin
Select @intTransactionCountOnEntry = @@TranCount BEGIN TRANSACTION
End
At the end of the procedure (and/or transaction), the developershould complete the transaction:
If @@TranCount > @intTransactionCountOnEntry Begin
If @intErrorCode = 0 COMMIT TRANSACTION Else
ROLLBACK TRANSACTION End
The solution will also perform well in the case of nested storedprocedures All procedures are rolled back using the same cascadingmechanism
The local variable@TransactionCountOnEntryis used totrack the number of opened transactions upon entry into a storedprocedure If the number is unaffected within the stored procedure,
Trang 23there is no reason either toCommitorRollbackwithin the
procedure The finished stored procedure looks like this:
Alter Procedure prInsertLeasedAsset_6
Insert leased asset and update total in LeaseSchedule.
Trang 24@intStatusId, @intLeaseId,
@intLeaseScheduleId,@intOwnerId,
@mnyLease, @intAcquisitionTypeID) Select @intErrorCode = @@Error,
@intInventoryId = @@identity end
If @intErrorCode = 0 begin
update total update LeaseSchedule Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease where LeaseId = @intLeaseId
Select @intErrorCode = @@Error end
If @@TranCount > @intTransactionCountOnEntry Begin
If @@Error = 0 COMMIT TRANSACTION Else
ROLLBACK TRANSACTION End
return @intErrorCode
XACT_ABORT
SQL Server does, in fact, have an equivalent to theOn Error Go Tocommand used by Visual Basic TheSET XACT_ABORTstatementforces SQL Server to roll back the complete transaction and stopfurther processing on the occurrence of any error
create Procedure prInsertLeasedAsset_7 Insert leased asset and update total in LeaseSchedule (demonstration of imperfect solution)
Trang 25Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease
where LeaseId = @intLeaseId
commit transaction
return (0)
Unfortunately, this solution presents a problem This statement
will also completely stop execution of the current batch The error
can still be detected and handled from the client application, but
inside the Transact-SQL code, SQL Server will treat it as a fatal error
Trang 26An important tool for implementing error handling is theRAISERRORstatement Its main purpose is to return a message to the user OpenQuery Analyzer and execute the following statement:
Raiserror ('Error occurred!', 0, 1)The server will display an error message in the Result pane (seeFigure 7-7)
The numbers specified as second and third parameters indicatethe severity and state of the error
Naturally, this statement does more than return this meagerresult It also sets the value of the@@errorglobal variable (function)
to the number of the error that you have raised If you do not specify
a number (as we did not in the previous example), SQL Server willassign an error number of 50000 to it
Figure 7-7. Using Raiserror
Trang 27You can also display errors that are predefined in SQL Server if
you reference them by their numbers, and you can also define your
own errors using the sp_addmessage system stored procedure:
Exec sp_addmessage 50001,
16, 'Unable to update Total of LeaseSchedule'Then you can display this message using the following statement:
Raiserror (50001, 16, 1)
The server will return the following:
Server: Msg 50001, Level 16, State 1, Line 1
Unable to update Total of LeaseSchedule
You can set the state and severity of the error and/or record the error
in the SQL Server Error Log, and even in the Windows NT Error Log:
Raiserror (50001, 16, 1) WITH LOG
SUMMARY
Some developers consider debugging the most difficult part of the
development process However, a systematic approach, common
sense, and modern debugging tools can significantly reduce the
effort required to solve errors
This chapter has presented an overview of bugs and the process
of debugging in general We have presented a systematic approach
to the debugging process We have discussed the configuration and
use of TSQL Debugger We have discussed debugging without TSQL
Debugger and looked at some of the most common errors found in
Transact-SQL
We have demonstrated two solutions for handling errors inside
Transact-SQL code You should choose one and make a habit of
using it Personally, I do not like to useXACT_ABORTbecause I
can exercise more control by investigating the@@errorfunction
Trang 28Critics might object to this solution, because it adds a significantamount of code to the script, and they might add that the solutionwould be improved if the developer could “hide” error handling toemphasize the statements that are performing the “real” processing.But the real value of this error handling solution is that it is a coherentsolution that permits the code in stored procedures to work in auniform manner and lets developers know what to expect when theunexpected occurs.
So, until Microsoft creates something new…
EXERCISES
1 Add debugging code in the following stored procedure:
Alter Procedure prSpaceUsedByTables_1 loop through table names in current database display info about amount of space used by each table As
Set nocount on declare @MaxCounter int,
@Counter int,
@TableName sysname
Create table #Tables (
Id int identity(1,1), TableName sysname)
collect table names insert into #Tables(TableName) select name
from sysobjects where xtype = 'U'
prepare loop Select @MaxCounter = Max(Id),
@Counter = 1 from #Tables
Trang 29while @Counter <= @MaxCounter
begin
get table name
select @TableName = TableName
from #Tables
where Id = @Counter
display space used
exec sp_spaceused @TableName
set @Counter = @Counter + 1
end
drop table #Tables
2 Execute the stored procedure through Query Analyzer to
review debugging information
3 Run the stored procedure through TSQL Debugger to try
debugging
4 What is the problem with the following code snippet?
update LeaseSchedule
Set PeriodicTotalAmount = PeriodicTotalAmount + @mnyLease
where LeaseId = @intLeaseId
5 Change the stored procedure from exercise 5 in Chapter 5
so that it complies with the error handling solution proposed
in this chapter
6 Take the stored procedure from exercise 7 in Chapter 4
and wrap it in the error handling solution described in
this chapter
Trang 31CHAPTER 8
Developing Professional Habits
317
Terms of Use
Trang 32This chapter discusses two critical aspects of applicationdevelopment:
▼ Source code control
▲ Naming conventionsThe very ideas of “control” and “convention” may be anathema
to some inexperienced developers who view themselves asunconventional characters outside the control of standard socialconstructs For experienced professionals, however, using sourcecode control and consistent naming conventions are not oneroustasks but ingrained habits and second nature Nothing differentiatesthe professional from the amateur like these two habits
THE CONCEPT OF SOURCE CODE CONTROL
Source code control (or version control) is typically introduced in
development environments where more than one developer needs
to work with the same piece of code If automated tools for sourcecode control are not employed, developers must contend with thefollowing issues:
▼ Manual integration of source code changes
■ Manual management of older versions of source code
▲ Greater risk of errors due to lack of constraintsMicrosoft provides a source code control package as an integralpart of its development tool set under the name Visual SourceSafe.This package allows developers to control their most valuable asset—source code You can also use the Visual SourceSafe database tomanage other file types such as Web content, documentation, and testdata, but our focus in this chapter is on how to use Visual SourceSafe
to manage the development cycle
Trang 33Introduction to Microsoft Visual SourceSafe
Microsoft’s primary purpose in developing Visual SourceSafe as a
part of its Visual Studio suite of development tools was to provide
a project-oriented means of storing and organizing code that would
allow developers to spend more time developing their projects than
managing them The emphasis is on ease of use and integration with
a wide range of development tools SQL Server 7.0 developers can
benefit greatly from this ease of use and integration, not only with
regard to source code, but also as a means of organizing all related
files such as project documentation and test data
As with SQL Server, there are different ways of implementing
Visual SourceSafe It is essentially a client/server application, but if
you are an independent developer, your development workstation
will likely also be your NT Server, SQL Server, and Visual SourceSafe
Server Of course, if you are an independent developer, you may be
wondering what need you have for source code control I will discuss
this issue later in the chapter For now you can take my word that
source code control is just as important for the solo developer working
on a simple project as it is for the large development team working on
a complex, component-based project
If you are a member of a development team, the Visual SourceSafe
client will allow you to work on local copies of code while preventing
other members of your team from overwriting your changes while you
have the code “checked out” from the Visual SourceSafe Server The
benefit of this simple concept is obvious, but you have to work with
and become comfortable with Visual SourceSafe before its many other
benefits will become just as obvious After you have posted your
source code, you can
▼ “Get” the current version of all files
■ “Check-out” a copy of a file that needs to be changed Visual
SourceSafe will prevent all other developers from changingthe file until it is returned (“checked-in”) to the VisualSourceSafe database
Trang 34■ See differences between a local (changed) version of a sourcecode file and the latest version recorded in the Visual
■ See changes between any two versions of a source code file
■ Deploy a project (on some development platforms such asthe Web)
■ Share common files between separate projects
▲ Make a single backup copy of the complete source code andall supporting files
Administering the Visual SourceSafe Database
Before you can use Visual SourceSafe, you need to create users andassign privileges to them
When you install Visual SourceSafe, you create just two users:
Admin and Guest The Admin user has all privileges on the database
and can also create other users The Guest user is initially limited toread-only access to source code files Both users are created with theirpassword set to an empty string (that is, blank) Since this stateconstitutes a threat to your source code, your first step should be toset the Admin password
To set the Admin password:
1 Open Visual SourceSafe Administrator (Select Start |Programs | Microsoft Visual Studio 6.0 | Microsoft VisualSourceSafe | Visual SourceSafe 6.0 Admin)
2 Select Admin in the Administrator window
3 Select Change Password on the Users menu The ChangePassword dialog appears (see Figure 8-1)
Trang 354 Leave the Old Password field blank (Remember, the initial
password is an empty string.)
5 Type the string you want to use as the Admin password in
the New Password field
6 Type the string again in the Verify field, then click OK
Now, let’s create another user:
1 Choose Add User on the Users menu
2 Specify a user name and password, verify the password, and
leave the Read-Only box unchecked, since you want to give
the new user both Read and Write permissions to the Visual
SourceSafe database
Figure 8-1. Visual SourceSafe Administrator
Trang 36TIP: If the Visual SourceSafe user name and password match the operating
system user name and password, the user will not have to type them eachtime she opens Visual SourceSafe on the local system Visual SourceSafewill pick them up automatically
NOTE: With Visual SourceSafe, you can assign more refined permission
levels such as Add, Rename, Delete, Check In, Check Out, Destroy, andRead To activate this wide-ranging control, click Tools | Options | ProjectSecurity and check the Enable Project Security option
Adding a Database to Visual SourceSafe
To demonstrate the implementation of source code control in adatabase project, you will add code from your sample Asset database
in Visual InterDev 6.0
1 Open the Asset database project in Visual InterDev
2 Open the Data View
3 Right-click the data connection (see Figure 8-2)
4 Select Add to Source Control on the pop-up menu and VisualInterDev will prompt you to create a new project in the VisualSourceSafe database:
Trang 375 Type the location of your Visual SourceSafe database (that is,
the location of the srcsafe.ini file)
Since Visual SourceSafe should be installed on the same
machine as SQL Server, the location of the Source Safe
database that you need to specify in this text box should be
relative to the server machine If you are developing from a
workstation that is separate from the “development” server,
you have to be careful how you enter the location of the
Visual SourceSafe database You should use the server’s
absolute path (for example: C:\Program Files\Microsoft
Visual Studio\Common\VSS) regardless of whether you
have that drive mapped on your workstation using another
drive letter such as S:
Figure 8-2. Creation of Data Connection in Visual Studio
Trang 38NOTE: On my machine, the Visual SourceSafe database is located in the
C:\Program Files\Microsoft Visual Studio\Common\VSS folder My computer,
in this case, is a development workstation, as well as the SQL Server andVisual SourceSafe server
6 Name the project and type a comment to describe the project
if you want The application will then prompt you for yourVisual SourceSafe user name (Login ID) and password
7 Type the user name and password you created earlier in thischapter and click OK to close this dialog and post the Assetdatabase to Visual SourceSafe
Visual SourceSafe creates a project and locks all stored procedures.You can see a small lock icon beside each stored procedure in DataView (see Figure 8-3)
NOTE: From this moment, you must check out a stored procedure before
you can change it Unfortunately, this solution does not prevent anotherdeveloper from using some other tool to change a stored procedure directly
in the database Visual SourceSafe only works through consensus Loosecannons can still wreak havoc on your development ship
Managing Stored Procedures
When stored procedures are locked, you can open them for viewing
in the editor, but Visual InterDev will prevent you from changingthem until you check them out: