. , , ,

,,,

MS SQL Server 9 Yukon. .NET — ,

(Sinclair)

(). 3700 , 855 ... , - ; , . , .

RSDN Team MS SQL Server. -, ( ), .

, , . , . .NET MS SQL Server.

, SQL. . SQL (PL/SQL, T-SQL). , , ( Interbase, MS SQL ..).

SQL, . SQL . , , . , PGP T-SQL ( , ). , , .

, . , DLL. , MD5 , .

Oracle Java . , Microsoft .

MS SQL Server .NET:

.

.

( ).

.

.

.NET Framework 1.2 .

, , .NET . (detach/attach) .

:

, T-SQL ( Query Analyzer. , MS SQL Server Workbench, ).

, MS Visual Studio .NET codename Whidbey.

, . .

T-SQL

CREATE ASSEMBLY:

CREATE ASSEMBLY assembly_name

[ AUTHORIZATION owner_name ]

FROM { < client_assembly_specifier > | < assembly_bits > [,...n] }

[ WITH PERMISSION_SET = { SAFE | EXTERNAL_ACCESS | UNSAFE } ]

< client_assembly_specifier > :: =

'[machine_name]share_name[path]manifest_file_name'

< assembly_bits > :: =

{ varbinary_literal | varbinary_expression }

. , USE database_name.

assembly_name .NET (assembly). , MS SQL Server, , .
AUTHORIZATION owner_name , . , , , IMPERSONATE. .
<client_assembly_specifier> , . . , , . , REFERENCES . , , , , .
assembly_bits . , , , . . - MS Visual Studio 8.0 (Whidbey).
PERMISSION_SET {SAFE | EXTERNAL_ACCESS | UNSAFE } , MS SQL Server . SAFE.SAFE . ( , , ).EXTERNAL_ACCESS MS SQL Server, . , - .UNSAFE , , . sysadmin. SAFE. , , - SQL Server . SAFE.

1. CREATE ASSEMBLY.

Visual Studio

- . , . Visual Studio . SQL Server Project ( Database Project!), Build Deploy, ( ) . Visual Studio , .

, Visual Studio T-SQL. , . ( !) . Microsoft.VisualStudio.DataTools.SqlAttributes.

SQL Server, . , ,

System.Data.Sql.SqlAssemblyAttribute. SQL Server Project AssemblyInfo.cs . :

[assembly: SqlAssembly(<name>, Authorization = <authorization>)]

name assembly_name CREATE ASSEMBLY, Authorization owner_name (. ).

, Visual Studio , , , . .

, . , .

, , , , , , .NET, , . Visual Studio Whidbey, :

, ( Build->Deploy). .

(PID) MS SQL Server. sqlservr.exe. , SQL Server, 3. Yukon MSDE, . , , SELECT ServerProperty('ProcessID')

. Debug->Attach to Process . , Attach.

. , . , .NET.

Debug->Detach All , . Visual Studio , Build.

MS SQL Server CREATE PROCEDURE . SQL Server Books Online:

CREATE PROC [ EDURE ] [schema_name.] procedure_name [ ; number ]

[ { @parameter data_type }

[ VARYING ] [ = default ] [ [ OUT [ PUT ]

] [ ,...n ]

[ WITH < procedure_option > [ ,...n ]

[ FOR REPLICATION ]

AS { < sql_statement > [ ...n ] | <.NET_Framework_reference> }

--

<.NET_Framework_reference> ::=

EXTERNAL NAME assembly_name:class_name[::method_name]

, T-SQL . :

( )

, . OUTPUT, .

, : SQLInt32, SQLInt16, System.Int32, System.Int16

REFERENCES.

.

C# :

using System;

using System.Data;

using System.Data.Sql;

using System.Data.SqlServer;

using System.Data.SqlTypes;

public class StoredProcedure

{

[SqlProcedure]

public static void MyProcedure()

{

}

};

, . , StoredProcedure.MyProcedure , (, Query Analyzer), , ( ).

SqlProcedure (System.Data.Sql.SqlProcedureAttribute). MS SQL Server. MS Visual Studio Whidbey , , CREATE PROCEDURE. , . , Name. [SqlProcedure("MyProcName")], MyProcName.

,

, , C#, . . :

using System;

using System.Data;

using System.Data.Sql;

using System.Data.SqlServer;

using System.Data.SqlTypes;

public class StoredProcedure

{

[SqlProcedure("HelloWorld")]

public static void MyProcedure()

{

SqlContext.GetPipe().Send("Hello, Yukon!");

}

};

, .NET MS SQL Server: System.Data.SqlServer.SqlContext. , , . System.Data.SqlServer.SqlPipe, . SQL Server . - , SqlPipe .

SqlPipe.Send(String msg), . print T-SQL. SqlPipe :

public void Execute (System.Data.SqlServer.SqlCommand command )public void Execute

(System.Data.SqlServer.SqlExecutionContext request )

. SELECT FROM T-SQL.
public void Send (System.Data.SqlServer.SqlError se) .
public void Send (System.Data.Sql.ISqlReader reader) .
public void SendResultsStart (System.Data.Sql.ISqlRecord record , bool sendRow) . SendingResults true.
public System.Boolean SendingResults { get; } , .
public void SendResultsRow (System.Data.Sql.ISqlRecord record)public void Send (System.Data.Sql.ISqlRecord record ) . SendingResults == true.
public void SendResultsEnd ( ) SendingResults false.

2.

, , , . .

, :

[SqlProcedure()]

public static void CurrencyCourse(

[SqlMapping(typeof(SqlDateTime))] DateTime start,

[SqlMapping(typeof(SqlDateTime))] DateTime end)

{

using (SqlCommand cmd = SqlContext.GetCommand())

{

cmd.CommandText = @"

select changeDate, course from Course

where changeDate between @start and @end";

cmd.Parameters.AddWithValue("@start", start);

cmd.Parameters.AddWithValue("@end", end);

DateTime current = start;

SqlDecimal course = SqlDecimal.Null; // ;

SqlMetaData[] recstruct = new SqlMetaData[2];

recstruct[0] = new SqlMetaData("D", SqlDbType.DateTime);

recstruct[1] = new SqlMetaData("course", SqlDbType.Decimal, 10, 4);

SqlDataRecord rec = new SqlDataRecord(recstruct);

SqlPipe pipe = SqlContext.GetPipe();

pipe.SendResultsStart(rec, false);

using (SqlDataReader r = cmd.ExecuteReader())

{

while (r.Read())

{

rec.SetSqlDecimal(1, course);

while(current < r.GetDateTime(0))

{

rec.SetDateTime(0, current);

pipe.SendResultsRow(rec);

current = current.AddDays(1);

}

course = r.GetDecimal(1);

}

}

rec.SetSqlDecimal(1, course);

while (current <= end)

{

rec.SetDateTime(0, current);

pipe.SendResultsRow(rec);

current = current.AddDays(1);

}

pipe.SendResultsEnd();

}

}

(Course) , , .

. (, MS VS Whidbey) SQL- , SqlMapping (System.Data.Sql.SqlMappingAttribute). . DateTime SQL datetime ( CLR System.Data.SqlTypes.SqlDateTime), .

, SqlContext SqlContext.GetCommand().

, , System.Data.Sql.ISqlRecord. System.Data.Sql.SqlDataRecord. . System.Data.Sql.SqlMetaData. . , SQL :

(

D datetime,

course decimal(10, 4)

)

, :

pipe.SendResultsStart(rec, false);

, ; .

SqlDataReader, , SqlDataRecord, . .

, ,

pipe.SendResultsEnd();

, , .. , , . . , .

T-SQL : .

, , .

.NET, . , . , . :

. .

System.Data.Sql.ISqlReader. . .

void. SqlContext.GetReturnResultSet(). .

.

, ( ). , :

select dbo.RevertString(Beavis rulez)

. reverse:

[SqlFunc()]

[SqlFunction(

DataAccess = DataAccessKind.None,

SystemDataAccess = SystemDataAccessKind.None,

IsDeterministic = true,

IsPrecise = true)]

public static SqlString RevertString(SqlString str)

{

if (str.IsNull)

return SqlString.Null;

System.Text.StringBuilder sb = new

System.Text.StringBuilder(str.Value.Length);

for (int i=str.Value.Length-1; i>=0; i--)

sb.Append(str.Value[i]);

return new SqlString(sb.ToString());

}

, , .

-, SqlFunc. SqlProcedure, , CREATE FUNCTION. , . .

SQLFunction MS SQL Server , . 3 :

DataAccess :DataAccessKind.None .DataAccessKind.Read .
SystemDataAccess :SystemDataAccessKind.None .SystemDataAccessKind.Read .
IsDeterministic , .. .
IsPrecise .

3.

, , , .

, , . , , e-mail. , .

ISqlReader

view , , SQL , . , , :

[SqlFunc(TableDefinition = "D datetime, course decimal(10, 4)")]

[SqlFunction(DataAccess = DataAccessKind.Read,

SystemDataAccess = SystemDataAccessKind.None,

IsDeterministic = false, IsPrecise = true)]

public static ISqlReader GetCourseChanges(DateTime start, DateTime end)

{

SqlCommand cmd = SqlContext.GetCommand();

cmd.CommandText = @"

select changeDate, course from Course

where changeDate between @start and @end";

cmd.Parameters.AddWithValue("@start", start);

cmd.Parameters.AddWithValue("@end", end);

return cmd.ExecuteReader();

}

, . Reader is closed. Reader , .

SqlResultSet

, , SqlContext.GetReturnResultSet(). , , . . , , / , . CurrencyCourse, :

[SqlFunc(TableDefinition = "D datetime, course decimal(10, 4) NULL")]

[SqlFunction(DataAccess = DataAccessKind.Read,

SystemDataAccess = SystemDataAccessKind.None,

IsDeterministic = false, IsPrecise = true)]

public static void GetCourseTable(DateTime start, DateTime end)

{

using (SqlCommand cmd = SqlContext.GetCommand())

{

cmd.CommandText = @"

select changeDate, course from Course

where changeDate between @start and @end";

cmd.Parameters.AddWithValue("@start", start);

cmd.Parameters.AddWithValue("@end", end);

DateTime current = start;

SqlDecimal course = SqlDecimal.Null;

SqlResultSet source = cmd.ExecuteResultSet(ResultSetOptions.None);

SqlResultSet dest = SqlContext.GetReturnResultSet();

SqlDataRecord rec;

while (source.Read())

{

while (current < source.GetDateTime(0))

{

rec = dest.CreateRecord();

rec.SetSqlDecimal(1, course);

rec.SetDateTime(0, current);

dest.Insert(rec);

current = current.AddDays(1);

}

course = source.GetDecimal(1);

}

while (current <= end)

{

rec = dest.CreateRecord();

rec.SetDateTime(0, current);

rec.SetSqlDecimal(1, course);

dest.Insert(rec);

current = current.AddDays(1);

}

}

}

, SqlFunction DataAccess = DataAccessKind.Read, , .

, SqlResultSet SqlDataReader. , , . , . .

. - MS SQL Server SUM, AVG OUNT.

CREATE AGGREGATE:

CREATE AGGREGATE [ schema_name. ] aggregate_name

( @param_name < input_sqltype > )

RETURNS < return_sqltype >

EXTERNAL NAME assembly_name [ :class_name ]

< input_sqltype > ::=

system_scalar_type | { [ udt_schema_name. ] udt_type_name }

< return_sqltype > ::=

system_scalar_type | { [ udt_schema_name. ] udt_type_name }

. . , , . :

public void Init()public void Init(input_type value) . . , SQL Server . value (input_type) , input_sqltype CREATE AGGREGATE.
public void Accumulate(input_type value) , . ( , GROUP BY, distinct . , , ). value , input_sqltype CREATE AGGREGATE.
public return_type Terminate() , , . , return_sqltype CREATE AGGREGATE.
public void Merge(udagg_type group) , SQL Server . , , . . . , .

4.

, ( SQL Server ). , , . , .

, , , N N- . ( N , - , N).

, . , N . N ( , 1/N) N Exp().

[Serializable]

[SqlUserDefinedAggregate(Format.Native, IsInvariantToDuplicates = false, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true)]

[StructLayout(LayoutKind.Sequential)]

public class AvgGeom: INullable

{

private double _agg;

private int _count;

private bool _isNull = true;

#region User-Defined Attribute Required Methods

public void Init()

{

_agg = 0;

_count = 0;

_isNull = true;

}

public void Accumulate(SqlDouble Value)

{

if (!Value.IsNull)

{

_agg += System.Math.Log(Value.Value);

_count++;

_isNull = false;

}

}

public void Merge(AvgGeom Group)

{

if (!Group.IsNull)

{

_agg += Group._agg;

_count += Group._count;

_isNull = false;

}

}

public SqlDouble Terminate()

{

if (IsNull)

return SqlDouble.Null;

else

return new SqlDouble(System.Math.Exp(_agg / _count));

}

#endregion

#region INullable Members

public bool IsNull

{

get

{

return _isNull;

}

}

#endregion

}

SqlUserDefinedAggregate, . ( 5).

Format . .
MaxByteSize . .
IsInvariantToDuplicates ( ). , MIN() , , SUM() . SQL Server Accumulate.
IsInvariantToNulls NULL- . ( COUNT()) .
IsNullIfEmpty , NULL . , MIN NULL , COUNT() 0.
IsInvariantToOrder ; , , Accumulate(). .

5.

( ) , . , , First() Last(), ( ), . , , , SQL . ORDER BY , , . ( ) ORDER BY . ( !) MS SQL Server Yukon SqlUserDefinedAggregateAttribute.IsInvariantToOrder , - . - .

, NULL, INullable. read-only bool IsNull. System.Data.SqlTypes . NULL , Null , -NULL Accumulate Merge.

SQL Server (User-defined Types, UDT). CLR- SQL Server. , ( ) -SQL. T-SQL.

T-SQL CREATE TYPE:

CREATE TYPE [ type_schema_name. ] type_name

{ [ FROM base_type [ ( precision [ , scale ] ) | ( 'urn:schema-namespace' ) ]

[ NULL | NOT NULL ] ]

| [ EXTERNAL NAME [ assembly_schema_name. ] assembly_name [ :class_name ] ]

}

.

T-SQL, , MS Visual Studio .Net Whidbey. , SqlUserDefinedType ( ) SQL Server Project.

, .NET SQL Server, :

. , , NULL ( ).

NULL-. INullable, . Null, NULL- , .. MyClass.Null.IsNull == true. Null, null.

: Parse(SqlString s) ToString().

. , ( ).

, . .

. , .

using System;

using System.Data.Sql;

using System.Data.SqlTypes;

using System.Text.RegularExpressions;

using System.Runtime.InteropServices;

[Serializable]

[SqlUserDefinedType(Format.Native)]

[StructLayout(LayoutKind.Sequential)]

public class SqlPoint: INullable

{

#region NULLability

private bool _isNull = true;

public bool IsNull

{

get

{

return _isNull;

}

}

public static SqlPoint Null

{

get

{

return new SqlPoint();

}

}

#endregion

#region

public override string ToString()

{

return IsNull? "null" : String.Format("X: {0}; Y: {1}", x, y);

}

public static SqlPoint Parse(SqlString s)

{ // ,

// ,

// ToString SqlPoint.

if (s.IsNull || s.Value.ToLower() == "null")

return Null;

SqlPoint p = new SqlPoint();

Regex t = new Regex(@"x:(?<x>d*(.d+)?)s*W*y:(?<y>d*(.d+)?)",

RegexOptions.IgnoreCase);

Match match = t.Match(s.Value);

p.x = SqlDouble.Parse(match.Groups["x"].Value);

p.y = SqlDouble.Parse(match.Groups["y"].Value);

return p;

}

#endregion

#region

private double _x=0;

private double _y=0;

public SqlDouble x

{

get

{

return IsNull ? SqlDouble.Null : new SqlDouble(_x);

}

set

{

if (!value.IsNull)

{

_x = value.Value;

_isNull = false;

}

}

}

public SqlDouble y

{

get { return IsNull? SqlDouble.Null: new SqlDouble(_y); }

set

{

if (!value.IsNull)

{

_y = value.Value;

_isNull = false;

}

}

}

public SqlDouble R // .

{

get

{

return IsNull

? SqlDouble.Null

: new SqlDouble(System.Math.Sqrt(_y*_y +_x*_x));

}

set

{

if (value.IsNull)

{

_isNull = true;

return;

}

double alpha = Alpha.IsNull? 0 : Alpha.Value;

_x = System.Math.Cos(alpha) * value.Value;

_y = System.Math.Sin(alpha) * value.Value;

}

}

public SqlDouble Alpha

{

get

{

return (IsNull)

? SqlDouble.Null

: new SqlDouble(System.Math.Atan2(_y, _x));

}

set

{

if (value.IsNull)

{

_isNull = true;

return;

}

double r = R.IsNull ? 0 : R.Value;

_x = System.Math.Cos(value.Value) * r;

_y = System.Math.Sin(value.Value) * r;

}

}

#endregion

}

:

declare @p SqlPoint

set @p::x = 3

set @p::y = 4

select @p::x, @p::y, @p::R, @p::ToString()

set @p::R = 10

select @p::x, @p::y, @p::R, @p::ToString()

set @p::Alpha = 0

select @p::x, @p::y, @p::R, @p::ToString()

set @p = convert(SqlPoint, ' x:6; y:5.00')

select @p::x, @p::y, @p::R, @p::ToString()

, 6:

@p::x @p::y @p::R @p::ToString()
3.0 4.0 5.0 X: 3; Y: 4
6.0000000000000009 7.9999999999999991 10.0 X: 6; Y: 8
10.0 0.0 10.0 X: 10; Y: 0
6.0 5.0 7.810249675906654 X: 6; Y: 5

6

. .

. get set , . , .

! , SQL Server , . , , .

T-SQL. , , .

, , .. . select SQL - . . , , , , T-SQL.

:

public SqlDouble ResetR(SqlDouble newR)

{

SqlDouble Result = R;

R = newR;

return Result;

}

:

declare @p SqlPoint

set @p::x=3

set @p::y=4

select @p::R

select @p::ResetR(10)

select @p::R

- ResetR . , .

, SQL Server . SqlMethod IsMutator, true. - . ResetR :

[SqlMethod(IsMutator=true, OnNullCall=false)]

public void ResetR2(SqlDouble newR)

{

R = newR;

}

SqlMethod

SqlMethod (System.Data.Sql.SqlMethodAttribute) SqlFunction, . . , IsMutator, . OnNullCall ; , NULL-. - , .

, . , . SQL Server .

Serializable System.Data.Sql.SqlUserDefinedTypeAttribute.

:

Format

// using System.Data.Sql

Format SqlUserDefinedTypeAttribute.Format {get; set}

. . :

Native - MS SQL Server . , . , , . .NET . , , , , . , System.String ( ) . , [StructLayout(LayoutKind.Sequential)]. SqlUserDefinedTypeAttribute.MaxByteSize.

SerializeDataWithMetaData . , Visual Studio (Project->Add New Item User-Defined Type). , . , Native , .

SerializeData Native SerializeDataWithMetaData. , , . ,

UserDefined , . MaxByteSize , IBinarySerialize. , Native- , .

MaxByteSize

// using System.Data.Sql

int SqlUserDefinedTypeAttribute.MaxByteSize {get; set}

. UserDefined- ( , ). SqlUserDefinedTypeAttribute.MaxByteSizeValue.

IsFixedLength

// using System.Data.Sql

bool SqlUserDefinedTypeAttribute.IsFixedLength {get; set}

, .

IsByteOrdered

// using System.Data.Sql

bool SqlUserDefinedTypeAttribute.IsByteOrdered {get; set}

, , . , . , MS SQL Server , , , order by group by, .

.NET , . , . , - .

T-SQL CREATE TRIGGER:

CREATE TRIGGER trigger_name

ON { table | view }

[ WITH ENCRYPTION ]

{

{ { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }

[ WITH APPEND ]

[ NOT FOR REPLICATION ]

AS

{ sql_statement [ ...n ] | EXTERNAL NAME < method specifier > }

}

}

< method_specifier > ::=

assembly_name:class_name[::method_name]

, MS Visual Studio Whidbey SQLTrigger:

string Name , trigger_name T-SQL.
string ForClause , . , "INSTEAD OF INSERT, FOR CREATE_ASSEMBLY ( , DDL- )
string Target , . DML- view, DDL- ALL SERVER , DATABASE, .

7.

. , : SqlTrigger(name, target, forClause) SqlTrigger(target, forClause).

, :

[SqlTrigger ("DATABASE", "AFTER CREATE_TABLE")]

public static void AttachAnotherTrigger()

{

SqlTriggerContext ctx = SqlContext.GetTriggerContext();

string xml = ctx.EventData.ToSqlString().Value;

Regex p = new Regex("<object>(?<tablename>.*)</object>",

RegexOptions.IgnoreCase);

string tableName = p.Match(xml).Groups["tablename"].Value;

SqlContext.GetPipe().Send(String.Format("Table {0} createdn", tableName));

using (SqlCommand cmd = SqlContext.GetCommand())

{

cmd.CommandText = String.Format(

@"create trigger {0}_insert on {0} for insert

as external name TestingYukon:CTriggerTest::AnotherTrigger",

tableName);

cmd.ExecuteNonQuery();

}

}

DDL- DML . , , SqlChars SqlTriggerContext.EventData. ( ) , , XML. , :

<EVENT_INSTANCE>

<PostTime>2004-01-15T04:13:59.600</PostTime>

<SPID>56</SPID>

<EventType>CREATE_TABLE</EventType>

<Database>Northwind</Database>

<Schema>dbo</Schema>

<Object>testtrigger</Object>

<ObjectType>TABLE</ObjectType>

<TSQLCommand>

<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON"

QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />

<CommandText>create table testtrigger(id int identity) </CommandText>

</TSQLCommand>

</EVENT_INSTANCE>

<object>, ( , XPath XSLT). T-SQL-:

create table testtrigger(id int identity)

insert into testtrigger default values

drop table testtrigger

--drop trigger AttachAnotherTrigger on database

MS Visual Studio Whidbey DML . , ( ) . .

EventData, SqlTriggerContext .

TriggerAction ( ) , , <EventType>, EventData.

DML- bool[] ColumnsUpdated , , . T-SQL UPDATE().

inserted deleted ; SqlCommand, GetCommand() SqlContext.

, :

using System;

using System.Data;

using System.Data.Sql;

using System.Data.SqlServer;

using System.Data.SqlTypes;

using System.Text.RegularExpressions;

public class CTriggerTest

{

[SqlTrigger ("DATABASE", "AFTER CREATE_TABLE")]

public static void AttachAnotherTrigger()

{

SqlTriggerContext ctx = SqlContext.GetTriggerContext();

Regex p = new Regex("<object>(?<tablename>.*)</object>",

RegexOptions.IgnoreCase);

string xml = ctx.EventData.ToSqlString().Value;

string tableName = p.Match(xml).Groups["tablename"].Value;

SqlContext.GetPipe().Send(String.Format("Table {0} createdn", tableName));

using (SqlCommand cmd = SqlContext.GetCommand())

{

cmd.CommandText = String.Format(

@"create trigger {0}_insert on {0} for insert

as external name TestingYukon:CTriggerTest::AnotherTrigger",

tableName);

cmd.ExecuteNonQuery();

}

}

public static void AnotherTrigger()

{

SqlContext.GetPipe().Send("Row Insert Interceptedn");

}

}

, AnotherTrigger . , .NET- T-SQL .

MS SQL Server Yukon, .

Yukon Generics

.NET 1.2 Generic-. , .

Yukon .NET, .

, Generic- Yukon . . . , , AvgGeom SqlDouble. . .

, generic- . Yukon . , -, , generic- . - ! GenericType<SQLDecimal> EXTERNAL NAME CREATE .

, generic-. , . :

public new void Init()

{

base.Init();

}

. -. , , . , .

. , .

, , - , . generic :

public interface IAggregating<input_type, return_type> : INullable

{

void Init();

void Accumulate(input_type value);

return_type Terminate();

void Merge(IAggregating<input_type, return_type> other);

}

Yukon . , .

Yukon

.NET- SQL Server , RDBMS. , . , .. CREATE ASSEMBLY.

-, Yukon binary. , TypeA, . . .

-, , - . Yukon . . ( , ).

Yukon

T-SQL . , . .

Yukon

.NET- CREATE ASSEMBLY . , -, , , , , Microsoft. , . CREATE ASSEMBLY, , , .

Yukon

RSDN , SQL-, JAVA, OSP . SQL/PSM, 1996 . , T-SQL . language, , , .NET. Microsoft , .NET.

Microsoft Development Environment Whidbey (8.0.30703.4),

Microsoft .NET Framework 1.2 (1.2.30703),

Microsoft SQL Server Yukon (9.00.608)

Microsoft Word 2003 (11.5604.5703)

Nescafe Gold ( 9198-330-605473-98)

RSDN Authoring Pack (3.1)

MSDN SQL Server Books Online.

http://www.rsdn.ru/



(Sinclair) (). 3700 , 855 ... , - ; ,

 

 

 

! , , , .
. , :