/*---------------------------------------------------------------------
$Header: /Perl/OlleDB/filestream.cpp 3 18-04-09 22:48 Sommar $
This file includes the support for OpenSqlFileStream.
Copyright (c) 2004-2018 Erland Sommarskog
$History: filestream.cpp $
*
* ***************** Version 3 *****************
* User: Sommar Date: 18-04-09 Time: 22:48
* Updated in $/Perl/OlleDB
* Added support for the new MSOLEDBSQL provider.
*
* ***************** Version 2 *****************
* User: Sommar Date: 15-05-24 Time: 21:06
* Updated in $/Perl/OlleDB
* Replaced check on _WIN64 with USE_64_BIT_INT, so that it works with
* 64-integers on 32-bit Perl.
*
* ***************** Version 1 *****************
* User: Sommar Date: 12-09-23 Time: 22:53
* Created in $/Perl/OlleDB
---------------------------------------------------------------------*/
#include "CommonInclude.h"
#include "handleattributes.h"
#include "convenience.h"
#include "init.h"
#include "internaldata.h"
#include "errcheck.h"
#include "filestream.h"
#include "senddata.h"
// Function prototype for OpenSqlFilestream.
typedef HANDLE (CALLBACK * OpenSqlFilestream_type)
(LPCWSTR, SQL_FILESTREAM_DESIRED_ACCESS, ULONG,
LPBYTE, SSIZE_T, PLARGE_INTEGER);
void * OpenSqlFilestream (SV * olle_ptr,
SV * path,
int access,
SV * sv_context,
unsigned int options,
SV * sv_alloclen)
{
BSTR bstr_path = SV_to_BSTR(path);
DBLENGTH context_len;
BYTE * context_ptr;
SQL_FILESTREAM_DESIRED_ACCESS acc = (SQL_FILESTREAM_DESIRED_ACCESS) access;
LARGE_INTEGER alloclen = {0, 0};
PLARGE_INTEGER alloclen_ptr = NULL;
int msgno;
internaldata * mydata = get_internaldata(olle_ptr);
const int namelen = 20;
char library_name[namelen];
// Set the library name.
if (mydata->provider == provider_msoledbsql) {
sprintf_s(library_name, namelen, "msoledbsql.dll");
}
else if (mydata->provider == provider_sqlncli11) {
sprintf_s(library_name, namelen, "sqlncli11.dll");
}
else if (mydata->provider == provider_sqlncli10) {
sprintf_s(library_name, namelen, "sqlncli10.dll");
}
else {
croak("To use OpenSqlFilestream you must use the SQLNCLI10 provider or later.\n");
}
// Try to get the library.
HMODULE libhandle = LoadLibraryA(library_name);
if (libhandle == NULL) {
msgno = GetLastError();
olle_croak(olle_ptr, "Load of %s failed with error %d.\n",
library_name, msgno);
}
// And then get a pointer to OpenSqlFilestream
OpenSqlFilestream_type OpenSqlFilestream_ptr = (OpenSqlFilestream_type)
GetProcAddress(libhandle, "OpenSqlFilestream");
if (OpenSqlFilestream_ptr == NULL) {
msgno = GetLastError();
olle_croak(olle_ptr,
"Could not get address for OpenSqlFilestream. Error code = %d\n",
msgno);
}
// Convert the context parameter toa binary value.
SV_to_binary(sv_context, OptBinaryAsStr(olle_ptr), FALSE, context_ptr,
context_len);
// Deal with the allocation length parameter.
if (my_sv_is_defined(sv_alloclen)) {
alloclen_ptr = &alloclen;
if (SvROK(sv_alloclen) &&
strncmp(SvPV_nolen(sv_alloclen), "HASH(", 5) == 0) {
HV * hv = (HV *) SvRV(sv_alloclen);
SV ** svp;
svp = hv_fetch(hv, "High", 4, 0);
if (svp != NULL && my_sv_is_defined(*svp)) {
alloclen.HighPart = (LONG) SvUV(*svp);
}
svp = hv_fetch(hv, "Low", 3, 0);
if (svp != NULL && my_sv_is_defined(*svp)) {
alloclen.LowPart = (DWORD) SvUV(*svp);
}
}
else {
#ifdef USE_64_BIT_INT
alloclen.QuadPart = SvUV(sv_alloclen);
#else
alloclen.HighPart = 0;
alloclen.LowPart = SvUV(sv_alloclen);
#endif
}
}
// Now we can cal OpenSqlFilestream.
HANDLE h = (*OpenSqlFilestream_ptr)(bstr_path, acc, options, context_ptr,
context_len, alloclen_ptr);
msgno = GetLastError();
SysFreeString(bstr_path);
Safefree(context_ptr);
if (h == INVALID_HANDLE_VALUE) {
BSTR msg = SysAllocStringLen(NULL, 200);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, msgno, 0, msg, 200, NULL);
for (SIZE_T ix = wcslen(msg) - 1; msg[ix] == L'\n' || msg[ix] == L'\r'; ix--) {
msg[ix] = L'\0';
}
msg_handler(olle_ptr, -msgno, 1, 16, msg,
NULL, NULL, 0, NULL, L"OpenSqlFilestream", 1, 1);
SysFreeString(msg);
}
// Free the libraru.
FreeLibrary(libhandle);
return h;
}