Comparing VFP and SQL Server 7.0 Datatypes

Michael Levy

Continuing his look at SQL Server 7.0 for Visual FoxPro developers, Michael examines the various SQL Server datatypes and how they interact with VFP.

The most basic tool a database implementor has for enforcing data integrity is the datatype. The datatype of a column controls what kind of data the column can contain. Actually, when you assign a datatype to a column, you specify up to four attributes:


Table 1 lists the more common SQL Server 7.0 datatypes.

Table 1. The more common SQL Server 7.0 datatypes.
Datatype Description
Binary Fixed length binary data (8000 bytes max)
Bit Either 0 or 1 (minimum 1 byte)
Char Fixed length, non-unicode data (8000 bytes max)
Datetime Date and time data with an accuracy of 3.33 ms. (8 bytes)
Decimal Fixed precision data with a range of -10^38 to 10^38 -1 (5-17 bytes depending on the precision)
Float Approximate precision data with a range of -1.79E+308 to 1.79E+308 (4-8 bytes)
Int Integer data with a range of -2^31 to 2^31 - 1 (4 bytes)
Image Variable length binary data (2^31 - 1 bytes max)
Money Currency values with a fixed scale of four (8 bytes)
nChar Fixed length, unicode data (4000 bytes max)
nVarchar Variable length, unicode data (4000 bytes max)
nText Variable length, unicode data (2^30 -1 bytes max)
Real Approximate precision data with a range of -3.4E+38 to 3.4E+38 (4 bytes)
Smalldatetime Date and time data with an accuracy of one minute (4 bytes)
Smallint Integer data with a range of -2^15 to 2^15 - 1 (2 bytes)
SmallMoney Currency value with a fixed scale of four (4 bytes)
Text Variable length, non-unicode data (2^31 - 1 bytes max)
Timestamp A value unique to the database and updated whenever a column changes (8 bytes)
Tinyint Integer data with a range of 0 to 255 (1 byte)
Uniqueidentifier A globally unique identifer
Varbinary Variable length binary data (8000 bytes max)
Varchar Variable length, non-unicode data (8000 bytes max)


Fixed vs. variable length
SQL Server 7.0's binary and character datatypes fall into two categories, fixed length and varying, or variable length. A fixed length column has a constant length no matter how much data is stored in the column. A char(9) will always be nine bytes. If you were to insert a value that had a length less than the column's, SQL Server would pad the column with spaces. Trying to insert a value that had a length larger than the columns would cause SQL Server to truncate the value so that it would fit within the column.

When you define a varying or variable length column, you specify the maximum length. For instance, a column defined as varchar(9) can contain a maximum of nine characters. Anything less than nine characters won't be padded, but anything more will be truncated.

Datatype mapping
SQL Server has 23 system datatypes. VFP has 13. Obviously, VFP maps multiple SQL Server datatypes to a single VFP datatype. Finding that mapping is easy.

The following is a SQL Server CREATE TABLE statement that will create a table using almost all of the SQL Server datatypes listed in Table 1:

 CREATE TABLE DataTypes (
   t_binary            binary(5) DEFAULT 0x1, 
   t_bit               bit DEFAULT '',
   t_datetime          datetime DEFAULT GETDATE(),
   t_decimal           decimal(5,2) DEFAULT 1.0,
   t_float             float DEFAULT 1.0,
   t_image             image NULL,
   t_int               int DEFAULT 1,
   t_money             money DEFAULT $1.0,
   t_nchar             nchar(5) DEFAULT '', 
   t_ntext             ntext NULL,
   t_nvarchar          nvarchar(5) DEFAULT '',
   t_real              real DEFAULT 1.0,
   t_smalldatetime     smalldatetime DEFAULT GETDATE(),
   t_smallint          smallint DEFAULT 1.0,
   t_smallmoney        smallmoney DEFAULT $1.0,
   t_text              text NULL,
   t_timestamp         timestamp,
   t_tinyint           tinyint DEFAULT 1,
   t_varbinary         varbinary(5) DEFAULT 0x1,
   t_varchar           varchar(5) DEFAULT '',
   t_uniqueidentifier  uniqueidentifier DEFAULT NEWID())


After the table has been created, you use the VFP SQLCOLUMNS() function to see how VFP maps the SQL Server datatypes. SQLCOLUMNS() is a VFP SQL Pass-Through (SPT) function that creates a VFP cursor containing one row for every column in the DataTypes table. Table 2 lists the results of executing SQLCOLUMNS().

 lcConnectString = "Driver=SQLServer;Server=testsql;" + ;
   "Database=pubs;Trusted_Connection=Yes"
 c= SQLSTRINGCONNECT(lcConnectString)
 r=SQLCOLUMNS(c)


Table 2. VFP's translation of SQL Server's datatypes.
Field_name Field_type Field_len Field_dec
T_BINARY M 4 0
T_BIT L 1 0
T_DATETIME T 8 0
T_DECIMAL N 7 2
T_FLOAT B 8 2
T_IMAGE G 4 0
T_INT I 4 0
T_MONEY Y 8 4
T_NCHAR C 5 0
T_NTEXT C 255 0
T_NVARCHAR C 5 0
T_REAL B 8 2
T_SMALLDATETIME T 8 0
T_SMALLINT I 4 0
T_SMALLMONEY Y 8 4
T_TEXT M 4 0
T_TIMESTAMP M 4 0
T_TINYINT I 4 0
T_VARBINARY M 4 0
T_VARCHAR C 5 0
T_UNIQUEIDENTIFIER C 36 0


VFP correctly maps bit, datetime, decimal, float, image, int, money, real, and text datatypes. It also correctly handles smalldatetime, smallint, and smallmoney by promoting them to the full-size VFP datatypes. Pay attention to the way that SQL Server's varchar datatype is handled. Since VFP can't support a variable length row, the easiest thing for VFP to do is use the maximum length that the column could be.

There are some surprises here. The first is how VFP handles the conversion of SQL Server's binary and varbinary datatypes. Both get converted to VFP's memo datatype. VFP does have a character (binary) datatype, but it's really a character with the no codepage translation (NOCPTRANS) option set.

The biggest surprise is the way that VFP handles SQL Server's ntext datatype. VFP maps the ntext datatype to a character(255)! But isn't the maximum length of a VFP character column 254? This seems to be a problem with VFP. I used Visual Basic's Data View window to examine the DataTypes table using both the ODBC driver and the OLE DB provider for SQL Server, and both reported the column as ntext.

Another surprise
Creating a remote view against the DataTypes table brought another surprise. The pure act of creating the view worked correctly:

 CREATE SQL VIEW vdatatypes REMOTE ;
   CONNECTION pubs_conn ;
 AS SELECT * FROM datatypes


Trying to open the vdatatypes view generated an error 1544 -- "DataType property for field `T_ntext' is invalid." Using the DBGETPROP() function to query the datatype of the vdatatypes.t_ntext column returned character(255). But opening the view in the view designer and examining the properties of the t_ntext column with the View Fields Properties dialog box revealed the data mapping to be character(20). By changing the length to 254 (or anything smaller), I was able to open the view.

And another . . .
Now that I could get the view open, I wanted to see how VFP handled the data stored within the Unicode datatypes (see the sidebar "The Unicode Standard" for more on Unicode). I populated the DataTypes table with several rows and retrieved the data using the VFP view. Did you ever notice that no matter how much data is in a row, your eyes always find the funky control characters? Well, terminating both the t_nchar and t_nvarchar fields was one of those funky control characters, and it turned out to be a 0x00 character. Even when I filled the column completely -- using a value like "12345" -- the data was truncated after the fourth position, and the last position was filled with a 0x00.

The t_ntext column didn't exhibit this problem, but I wonder if the 0x00 character is hidden in the missing character in the 255th position.

The UseMemoSize cursor property
This property will affect the datatype mappings. If the SQL Server character column has a length that's greater than the value specified by UseMemoSize, VFP will convert the column to a memo datatype when it retrieves it. You can use the CURSORSETPROP() function to change the UseMemoSize property from its default value of 255.

The disclaimer
I used the following products and versions for this article. I'm listing them because our industry and tools change so fast that the behavior of a product can change from version to version:


The end
Hopefully, I've provided additional insight into the datatypes that both SQL Server and VFP offer. Having a clear-cut example of how the datatypes of the two systems interact should make it easier to design and predict the data-transformation behavior of your applications.

Michael Levy is a consultant with ISResearch, Inc., a Microsoft Solution Provider and Certified Technical Education Center. He's a Microsoft Certified Solution Developer and Trainer. Michael specializes in using Visual Studio and SQL Server to solve business problems. mlevy@isresearch.com.


Sidebar: The Unicode Standard
The problem with using a single byte to encode a character is that only 256 characters can be represented. In order to support multiple alphabets, different encoding schemes (code pages) must be created. The Unicode standard was developed with the primary goal of providing one character-encoding scheme for all alphabetic characters, ideographic characters, and symbols. Using a 16-bit encoding scheme enables a total of over 65,000 characters to be encoded. Currently, version 2 of the Unicode standard contains more than 38,000 characters and symbols from the world's languages and mathematics.

SQL Server 7.0 includes three new datatypes for storing Unicode data: nchar, nvarchar, and ntext (the prefix n comes from the SQL 92 standard for National datatypes). The Unicode datatypes are identical to their non-Unicode cousins, except they take up more space and can only store half as much data (4000 bytes vs. 8000 bytes).

For more information about the Unicode Standard, visit the Unicode Consortium Web site at >http://www.unicode.org.