Quais são os formatos de armazenamento binário para SQFLT8, SQLMoney e outros tipos de dados nativos do SQL?
-
21-09-2019 - |
Pergunta
De acordo com a documentação, os dados nativos (binários) podem ser importados ou exportados com formatados BCP nos formatos de dados nativos do SQL Server. Exemplos destes são SQLFLT8, SQLFLT4, SQLMONEY ou SQLNUMERIC.
Alguém sabe quais são os formatos de dados para os vários tipos ou onde a documentação especificando esses formatos pode ser encontrada. Por exemplo, um SQLFLT8 é armazenado como um número de precisão dupla IEEE ou em algum outro formato?
Editar: Das respostas por Kevchadders e Andrew Eu tive um pouco de epifania fiz um pouco de Google para #Define e Typedef para ver se conseguia encontrar arquivos de cabeçalho C com definições. Isso surgiu com um arquivo odbcdss.h
; a responda Eu publiquei abaixo algumas exaltadas do arquivo, o que parece bastante promissor.
Solução
Não tenho certeza se a teoria se manterá, mas descobrir o armazenamento interno dos tipos pode ser alcançado usando algum SQL e um pouco de descoberta. Eu fiz isso para o novo DateTime2 / DateTimeOffset no meu blog para obter o formato binário interno, pois estava interessado em ver como eles obtiveram precisão adicional.
Como exemplo de dinheiro
declare @test money
set @test = 12.34
select @test -- shows 12.34 as expected
declare @binaryValue binary(8)
set @binaryvalue = convert(binary(8),@test)
select @binaryvalue
Saída: 0x000000000001E208
Isso é 123400, quando considerado um número decimal, o dinheiro é armazenado em 4 locais decimais, o que indicaria 12.3400 como o valor, revertendo isso em teoria, um valor de apenas 1 em hexadecimal deve ser 0,0001
declare @test money
declare @binaryValue binary(8)
set @binaryvalue = 0x0000000000000001
set @test = convert(money,@binaryvalue)
select @test
Saídas 0,0001
A próxima coisa que eu verificaria são os números negativos,
declare @test money
set @test = -12.34
select @test -- shows -12.34 as expected
declare @binaryValue binary(8)
set @binaryvalue = convert(binary(8),@test)
select @binaryvalue
Saída: 0xffffffffffe1df8
Então, parece que é um número de 8 bytes assinado, pois apenas retira o número do FF ... etc. Uma verificação rápida com -0.0001 fornece todos os 0xfff .... fff conforme o esperado e -0.0002 fornece 0xff .... ffe conforme o esperado.
Se isso vale para o BCP, não tenho certeza, mas como um formato de armazenamento interno, eu adivinharia um número inteiro de 8 bytes assinado que tem 4 locais decimais assumidos.
Outras dicas
Alguns pesquisando mais no Google para #define e typedef em conjunto com os tipos de dados, apareceu este arquivo de cabeçalho (odbcss.h
) vinculado aqui.. A primeira linha possui #Defines for Magic Constants que correspondem diretamente aos nomes dos tipos de dados SQL. O snippet inferior possui alguns tipos de letra e definições de estrutura para formatos de dados de aparência sensata para os tipos.
Parece que essas podem ser as definições de formato relevantes.
Os trechos relevantes são:
// SQL Server Data Type Tokens. Returned by SQLColAttributes/SQL_CA_SS_COLUMN_SSTYPE.
#define SQLTEXT 0x23
#define SQLVARBINARY 0x25
#define SQLINTN 0x26
#define SQLVARCHAR 0x27
#define SQLBINARY 0x2d
#define SQLIMAGE 0x22
#define SQLCHARACTER 0x2f
#define SQLINT1 0x30
#define SQLBIT 0x32
#define SQLINT2 0x34
#define SQLINT4 0x38
#define SQLMONEY 0x3c
#define SQLDATETIME 0x3d
#define SQLFLT8 0x3e
#define SQLFLTN 0x6d
#define SQLMONEYN 0x6e
#define SQLDATETIMN 0x6f
#define SQLFLT4 0x3b
#define SQLMONEY4 0x7a
#define SQLDATETIM4 0x3a
#define SQLDECIMAL 0x37
#define SQLDECIMALN 0x6a
#define SQLNUMERIC 0x3f
#define SQLNUMERICN 0x6c
[ . . . ]
typedef char DBCHAR;
typedef unsigned char DBBINARY;
typedef unsigned char DBTINYINT;
typedef short DBSMALLINT;
typedef unsigned short DBUSMALLINT;
typedef long DBINT;
typedef double DBFLT8;
typedef unsigned char DBBIT;
typedef unsigned char DBBOOL;
typedef float DBFLT4;
typedef DBFLT4 DBREAL;
typedef UINT DBUBOOL;
typedef struct dbvarychar
{
DBSMALLINT len;
DBCHAR str[DBMAXCHAR];
} DBVARYCHAR;
typedef struct dbvarybin
{
DBSMALLINT len;
BYTE array[DBMAXCHAR];
} DBVARYBIN;
typedef struct dbmoney
{ // Internal representation of MONEY data type
LONG mnyhigh; // Money value *10,000 (High 32 bits/signed)
ULONG mnylow; // Money value *10,000 (Low 32 bits/unsigned)
} DBMONEY;
typedef struct dbdatetime
{ // Internal representation of DATETIME data type
LONG dtdays; // No of days since Jan-1-1900 (maybe negative)
ULONG dttime; // No. of 300 hundredths of a second since midnight
} DBDATETIME;
typedef struct dbdatetime4
{ // Internal representation of SMALLDATETIME data type
USHORT numdays; // No of days since Jan-1-1900
USHORT nummins; // No. of minutes since midnight
} DBDATETIM4;
typedef LONG DBMONEY4; // Internal representation of SMALLMONEY data type
// Money value *10,000
#define DBNUM_PREC_TYPE BYTE
#define DBNUM_SCALE_TYPE BYTE
#define DBNUM_VAL_TYPE BYTE
typedef const LPBYTE LPCBYTE;
typedef DBINT * LPDBINT;
#if (ODBCVER < 0x0300)
#define MAXNUMERICLEN 16
typedef struct dbnumeric
{ // Internal representation of NUMERIC data type
DBNUM_PREC_TYPE precision; // Precision
DBNUM_SCALE_TYPE scale; // Scale
BYTE sign; // Sign (1 if positive, 0 if negative)
DBNUM_VAL_TYPE val[MAXNUMERICLEN]; // Value
} DBNUMERIC;
typedef DBNUMERIC DBDECIMAL;// Internal representation of DECIMAL data type
#else // Use ODBC 3.0 definitions since same as DBLib
#define MAXNUMERICLEN SQL_MAX_NUMERIC_LEN
typedef SQL_NUMERIC_STRUCT DBNUMERIC;
typedef SQL_NUMERIC_STRUCT DBDECIMAL;
#endif
#endif // MAXNUMERICLEN
Boa pergunta.
Não parece muito na web sobre isso, mas eu achei isso Tipos de armazenamento de arquivos nativos (Segunda tabela para baixo), que mostra cada tipo de armazenamento de arquivo nativo e o que é gravado no tipo de dados do arquivo de host correspondente.
por exemplo, float = sqlflt8
real = sqlflt4
dinheiro = sqlmoney
numérico = sqlnumeric
Desculpas se você já se deparou com esta lista.