├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── cpp ├── IsolateTests │ └── dart_mssql.lib ├── dart_mssql.sln └── dart_mssql │ ├── dart_mssql.cpp │ ├── dart_mssql.h │ ├── dart_mssql.vcxproj │ ├── dart_mssql.vcxproj.filters │ ├── dart_mssql.vcxproj.user │ ├── dart_mssql_common.cpp │ ├── dart_mssql_connection.cpp │ ├── dart_mssql_dllmain_win.cpp │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h ├── dart_mssql_32.dll ├── dart_mssql_64.dll ├── example ├── dart_mssql_32.dll ├── dart_mssql_64.dll └── main.dart ├── lib ├── dart_mssql.dart └── src │ └── sql_connection.dart └── pubspec.yaml /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve our package 4 | title: "[BUG]" 5 | labels: '' 6 | assignees: MoacirSchmidt 7 | 8 | --- 9 | 10 | **Screenshots** 11 | Please attach screenshots showing error message or bug behavior 12 | 13 | **To Reproduce** 14 | Complete dart code which reproduces the problem: 15 | 16 | **Desktop (please complete the following information):** 17 | - Windows version: 18 | - Dart VM version (ouput of dart --version): 19 | - MS-SQL version: 20 | - Authentication mode (SQL Server Authentication, Windows Authentication, Active Directory): 21 | - dart_mssql package version [e.g. 0.2.3]: 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | **/*.class 3 | **/*.lock 4 | **/*.log 5 | **/*.pyc 6 | **/*.swp 7 | **/.DS_Store 8 | **/.history 9 | **/.atom/ 10 | **/.buildlog/ 11 | **/.svn/ 12 | **/config.yaml 13 | 14 | # C++ generated files 15 | **/*.dll 16 | **/*.exe 17 | **/*.ilk 18 | **/*.obj 19 | **/*.iobj 20 | **/*.ipdb 21 | **/*.ipch 22 | **/*.exp 23 | **/*.pdb 24 | **/*.pch 25 | **/*.idb 26 | **/*.tlog 27 | **/*.suo 28 | **/*.opendb 29 | 30 | # IntelliJ related 31 | **/*.iml 32 | **/*.ipr 33 | **/*.iws 34 | **/.idea/ 35 | 36 | # Visual Studio Code related 37 | **/.vscode/ 38 | **/.vs/ 39 | **/Debug/ 40 | **/Release/ 41 | **/x64/ 42 | **/x86/ 43 | 44 | # Flutter/Dart/Pub related 45 | **/doc/api/ 46 | **/.dart_tool/ 47 | **/.flutter-plugins 48 | **/.packages 49 | **/.pub-cache/ 50 | **/.pub/ 51 | **/build/ 52 | 53 | # Android related 54 | **/android/**/gradle-wrapper.jar 55 | **/android/.gradle 56 | **/android/captures/ 57 | **/android/gradlew 58 | **/android/gradlew.bat 59 | **/android/local.properties 60 | **/android/**/GeneratedPluginRegistrant.java 61 | 62 | # iOS/XCode related 63 | **/ios/**/*.mode1v3 64 | **/ios/**/*.mode2v3 65 | **/ios/**/*.moved-aside 66 | **/ios/**/*.pbxuser 67 | **/ios/**/*.perspectivev3 68 | **/ios/**/*sync/ 69 | **/ios/**/.sconsign.dblite 70 | **/ios/**/.tags* 71 | **/ios/**/.vagrant/ 72 | **/ios/**/DerivedData/ 73 | **/ios/**/Icon? 74 | **/ios/**/Pods/ 75 | **/ios/**/.symlinks/ 76 | **/ios/**/profile 77 | **/ios/**/xcuserdata 78 | **/ios/.generated/ 79 | **/ios/Flutter/App.framework 80 | **/ios/Flutter/Flutter.framework 81 | **/ios/Flutter/Generated.xcconfig 82 | **/ios/Flutter/app.flx 83 | **/ios/Flutter/app.zip 84 | **/ios/Flutter/flutter_assets/ 85 | **/ios/ServiceDefinitions.json 86 | **/ios/Runner/GeneratedPluginRegistrant.* 87 | 88 | # Exceptions to above rules. 89 | !**/dart_mssql_32.dll 90 | !**/dart_mssql_64.dll 91 | !**/ios/**/default.mode1v3 92 | !**/ios/**/default.mode2v3 93 | !**/ios/**/default.pbxuser 94 | !**/ios/**/default.perspectivev3 95 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 96 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.0.0] 2 | 3 | * Released for production use 4 | 5 | ## [0.2.6] 6 | 7 | * lastIdentify fix! 8 | 9 | ## [0.2.5] 10 | 11 | * Health suggestions adjustments 12 | 13 | ## [0.2.4] 14 | 15 | * DBTYPE_NUMERIC bug fix! -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Polygonus 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dart_mssql 2 | 3 | High Performance Microsoft SQL Server (MS-SQL Server) Driver for Dart (32 & 64bits) 4 | 5 | # Important 6 | 7 | - This package is not suitable for flutter or web projects. It only runs on server-side apps. 8 | - It works only on Windows (32bits or 64bits) 9 | - You have to install OLE DB Driver 10 | - You have to install Microsoft Visual C++ Redistributable 11 | - dart_mssql_32.dll (32-bit) and dart_mssql_64.dll (64-bit) are the compiled versions of the driver. Rename to "dart_mssql.dll" according to your needs and copy it to the main directory of your project. 12 | 13 | # Example Usage 14 | 15 | Demo code to perform Raw SQL queries 16 | 17 | ```dart 18 | import 'dart:io'; 19 | import 'package:dart_mssql/dart_mssql.dart'; 20 | 21 | void main() async { 22 | SqlConnection connection = SqlConnection(host:"SERVERNAME", db:"DBNAME", user:"USERNAME", password:"PASSWORD"); 23 | String cmd = "select email from usuario where id_usuario=?"; 24 | 25 | SqlResult result = connection.execute(cmd,[4]); 26 | result.rows.forEach((e) { 27 | print("${e.email}"); 28 | }); 29 | print("end of printing."); 30 | connection.close(); 31 | stdin.readLineSync(); 32 | } 33 | ``` 34 | 35 | # Troubleshooting 36 | 37 | ``` 38 | Problem: 39 | The specified module could not be found. 40 | error: library handler failed 41 | 42 | Cause: 43 | Missing installing Microsoft OLE DB Driver OR missing dart_mssql.dll file into project main directory OR missing Microsoft Visual C++ Redistributable 44 | 45 | Solution: 46 | Copy dart_mssql.dll file into project main directory. 47 | 48 | 49 | Problem: 50 | %1 is not a valid Win32 application. 51 | error: library handler failed 52 | 53 | Cause: 54 | incorrect dart_mssql.dll version (32 bits with dart VM 64 bits or vice versa) 55 | 56 | Solution: 57 | Copy correct dart_mssql.dll file into project main directory. 58 | 59 | 60 | ``` 61 | # Compiling with Microsoft Visual Studio 2017 Community Edition 62 | 63 | IF AND ONLY IF you want to compile library source code (C++ part) follow the instructions below: 64 | 65 | - Before compile, you have to install Windows 10 SDK on your Microsoft Visual Studio 2017 Community Edition 66 | - Open solution file dart_mssql\cpp\dart_mssql.sln with Microsoft Visual Studio 2017 Community Edition 67 | - On "Solution Explorer" Panel right click on dart_mssql project and select "Rebuild" 68 | - Put the generated dart_mssql.dll file into your project main folder (same folder of your pubspec.yaml file) 69 | - Be sure to have correct dart-sdk\bin folder (32 or 64 bits) in VC++ Directories -> Library Directories. Change "F:\DartSDK64\dart-sdk\bin" to your location 70 | - Be sure to have correct dart.lib version (32 or 64 bits) in Linker -> Input -> Additional Dependencies. Change "F:\DartSDK64\dart-sdk\bin\dart.lib" to your location 71 | -------------------------------------------------------------------------------- /cpp/IsolateTests/dart_mssql.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/cpp/IsolateTests/dart_mssql.lib -------------------------------------------------------------------------------- /cpp/dart_mssql.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.168 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dart_mssql", "dart_mssql\dart_mssql.vcxproj", "{D9A13674-7FA5-47D4-8E78-64C75166B926}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | PokerDebug|x64 = PokerDebug|x64 13 | PokerDebug|x86 = PokerDebug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Debug|x64.ActiveCfg = Debug|x64 19 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Debug|x64.Build.0 = Debug|x64 20 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Debug|x86.ActiveCfg = Debug|Win32 21 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Debug|x86.Build.0 = Debug|Win32 22 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.PokerDebug|x64.ActiveCfg = IsolateTests|x64 23 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.PokerDebug|x64.Build.0 = IsolateTests|x64 24 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.PokerDebug|x86.ActiveCfg = IsolateTests|Win32 25 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.PokerDebug|x86.Build.0 = IsolateTests|Win32 26 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Release|x64.ActiveCfg = Release|x64 27 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Release|x64.Build.0 = Release|x64 28 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Release|x86.ActiveCfg = Release|Win32 29 | {D9A13674-7FA5-47D4-8E78-64C75166B926}.Release|x86.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {99417B45-38B8-4A45-95FB-7732A6538FF5} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql.cpp: -------------------------------------------------------------------------------- 1 | // dart_mssql.cpp : Defines the exported functions for the DLL application. 2 | // 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "msoledbsql.h" 8 | #include "dart_api.h" 9 | #include "dart_native_api.h" 10 | #include "dart_mssql.h" 11 | 12 | Dart_Handle HandleError(Dart_Handle handle) { 13 | if (Dart_IsError(handle)) Dart_PropagateError(handle); 14 | return handle; 15 | } 16 | 17 | Dart_Handle dartMssqlLib; 18 | Dart_Handle sqlResultClass; 19 | Dart_Handle sqlReturnClass; 20 | 21 | void registerHandleInGlobalInterfaceTable(IDBInitialize* pSession, Dart_Handle dartSqlReturn, int* errorCount, std::string* errorMessages) { 22 | HRESULT hr; 23 | 24 | IGlobalInterfaceTable* pGIT = NULL; 25 | hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 26 | NULL, 27 | CLSCTX_INPROC_SERVER, 28 | IID_IGlobalInterfaceTable, 29 | (void**)&pGIT); 30 | DWORD dwCookie = 0; 31 | if (oleCheck(hr, pSession, IID_IDBInitialize, errorCount, errorMessages) >= 0) { 32 | hr = pGIT->RegisterInterfaceInGlobal(pSession, IID_IDBInitialize, &dwCookie); 33 | if (oleCheck(hr, pSession, IID_IDBInitialize, errorCount, errorMessages) >= 0) { 34 | HandleError(Dart_SetField(dartSqlReturn, Dart_NewStringFromCString("handle"), Dart_NewIntegerFromUint64(dwCookie))); 35 | } 36 | } 37 | } 38 | 39 | IDBInitialize* getHandleFromGlobalInterfaceTable(DWORD cookie, int* errorCount, std::string* errorMessages) { 40 | IDBInitialize* pSession = NULL; 41 | HRESULT hr; 42 | IGlobalInterfaceTable* pGIT = NULL; 43 | hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 44 | NULL, 45 | CLSCTX_INPROC_SERVER, 46 | IID_IGlobalInterfaceTable, 47 | (void**)&pGIT); 48 | if (oleCheck(hr, NULL, GUID_NULL, errorCount, errorMessages) >= 0) { 49 | hr = pGIT->GetInterfaceFromGlobal(cookie, IID_IDBInitialize, (void**)&pSession); 50 | oleCheck(hr, NULL, GUID_NULL, errorCount, errorMessages); 51 | } 52 | return pSession; 53 | } 54 | 55 | void revokeInterfaceFromGlobalInterfaceTable(DWORD cookie) { 56 | HRESULT hr; 57 | IGlobalInterfaceTable* pGIT = NULL; 58 | hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 59 | NULL, 60 | CLSCTX_INPROC_SERVER, 61 | IID_IGlobalInterfaceTable, 62 | (void**)&pGIT); 63 | if (hr == S_OK) { 64 | hr = pGIT->RevokeInterfaceFromGlobal(cookie); 65 | } 66 | } 67 | 68 | void _connectCommand(Dart_NativeArguments arguments) { 69 | const char *serverName; 70 | const char *databaseName; 71 | const char *userName; 72 | const char *password; 73 | int64_t authType; 74 | int errorCount = 0; 75 | std::string errorMessages; 76 | IDBInitialize* pSession = NULL; 77 | HRESULT hr = S_OK; 78 | 79 | Dart_EnterScope(); 80 | 81 | HandleError(Dart_StringToCString(HandleError(Dart_GetNativeArgument(arguments, 0)), &serverName)); 82 | HandleError(Dart_StringToCString(HandleError(Dart_GetNativeArgument(arguments, 1)), &databaseName)); 83 | HandleError(Dart_StringToCString(HandleError(Dart_GetNativeArgument(arguments, 2)), &userName)); 84 | HandleError(Dart_StringToCString(HandleError(Dart_GetNativeArgument(arguments, 3)), &password)); 85 | HandleError(Dart_IntegerToInt64(HandleError(Dart_GetNativeArgument(arguments, 4)), &authType)); 86 | dartMssqlLib = HandleError(Dart_LookupLibrary(Dart_NewStringFromCString("package:dart_mssql/src/sql_connection.dart"))); 87 | sqlResultClass = HandleError(Dart_GetType(dartMssqlLib, Dart_NewStringFromCString("SqlResult"), 0, NULL)); 88 | sqlReturnClass = HandleError(Dart_GetType(dartMssqlLib, Dart_NewStringFromCString("_SqlReturn"), 0, NULL)); 89 | 90 | Dart_Handle dartSqlReturn = HandleError(Dart_New(sqlReturnClass, Dart_Null(), 0, NULL)); 91 | sqlConnect(serverName, databaseName, userName, password, authType, &pSession, &errorCount, &errorMessages); 92 | if (errorCount == 0) { 93 | registerHandleInGlobalInterfaceTable(pSession, dartSqlReturn, &errorCount, &errorMessages); 94 | }; 95 | if (errorCount != 0) { 96 | HandleError(Dart_SetField(dartSqlReturn, Dart_NewStringFromCString("error"), Dart_NewStringFromCString(errorMessages.c_str()))); 97 | } 98 | Dart_SetReturnValue(arguments, dartSqlReturn); 99 | Dart_ExitScope(); 100 | } 101 | 102 | void _executeCommand(Dart_NativeArguments arguments) { 103 | const char *sqlCommand; 104 | int64_t handle; 105 | int errorCount = 0; 106 | std::string errorMessages; 107 | IDBInitialize* pSession = NULL; 108 | 109 | Dart_EnterScope(); 110 | 111 | HandleError(Dart_IntegerToInt64(HandleError(Dart_GetNativeArgument(arguments, 0)), &handle)); 112 | HandleError(Dart_StringToCString(HandleError(Dart_GetNativeArgument(arguments, 1)), &sqlCommand)); 113 | Dart_Handle sqlParams = HandleError(Dart_GetNativeArgument(arguments, 2)); 114 | dartMssqlLib = HandleError(Dart_LookupLibrary(Dart_NewStringFromCString("package:dart_mssql/src/sql_connection.dart"))); 115 | sqlResultClass = HandleError(Dart_GetType(dartMssqlLib, Dart_NewStringFromCString("SqlResult"), 0, NULL)); 116 | sqlReturnClass = HandleError(Dart_GetType(dartMssqlLib, Dart_NewStringFromCString("_SqlReturn"), 0, NULL)); 117 | 118 | pSession = getHandleFromGlobalInterfaceTable((DWORD)handle, &errorCount, &errorMessages); 119 | Dart_Handle dartSqlReturn = HandleError(Dart_New(sqlReturnClass, Dart_Null(), 0, NULL)); 120 | Dart_Handle dartSqlResult = HandleError(Dart_New(sqlResultClass, Dart_Null(), 0, NULL)); 121 | if (errorCount == 0) { 122 | BSTR sqlCmd = UTF8ToBSTR(sqlCommand); 123 | sqlExecute(pSession, sqlCmd, sqlParams, dartMssqlLib, dartSqlResult, &errorCount, &errorMessages); 124 | } 125 | if (errorCount != 0) { 126 | HandleError(Dart_SetField(dartSqlReturn, Dart_NewStringFromCString("error"), Dart_NewStringFromCString(errorMessages.c_str()))); 127 | } 128 | else { 129 | HandleError(Dart_SetField(dartSqlReturn, Dart_NewStringFromCString("result"), dartSqlResult)); 130 | } 131 | 132 | Dart_SetReturnValue(arguments, dartSqlReturn); 133 | Dart_ExitScope(); 134 | } 135 | 136 | void _disconnectCommand(Dart_NativeArguments arguments) { 137 | uint64_t handle; 138 | int errorCount = 0; 139 | std::string errorMessages; 140 | IDBInitialize* pSession = NULL; 141 | 142 | Dart_EnterScope(); 143 | 144 | HandleError(Dart_IntegerToUint64(HandleError(Dart_GetNativeArgument(arguments, 0)), &handle)); 145 | pSession = getHandleFromGlobalInterfaceTable((DWORD)handle, &errorCount, &errorMessages); 146 | revokeInterfaceFromGlobalInterfaceTable((DWORD)handle); 147 | if (pSession) { 148 | pSession->Release(); 149 | } 150 | Dart_ExitScope(); 151 | } 152 | 153 | struct FunctionLookup { 154 | const char* name; 155 | Dart_NativeFunction function; 156 | }; 157 | 158 | FunctionLookup function_list[] = { 159 | {"_executeCommand", _executeCommand}, 160 | {"_connectCommand", _connectCommand}, 161 | {"_disconnectCommand", _disconnectCommand}, 162 | {NULL, NULL} 163 | }; 164 | 165 | Dart_NativeFunction nativeResolver(Dart_Handle name, int argc, bool * autoSetupScope) { 166 | if (!Dart_IsString(name)) { 167 | return NULL; 168 | } 169 | Dart_NativeFunction result = NULL; 170 | if (autoSetupScope == NULL) { 171 | return NULL; 172 | } 173 | 174 | Dart_EnterScope(); 175 | const char* cname; 176 | HandleError(Dart_StringToCString(name, &cname)); 177 | 178 | for (int i = 0; function_list[i].name != NULL; ++i) { 179 | if (strcmp(function_list[i].name, cname) == 0) { 180 | *autoSetupScope = true; 181 | result = function_list[i].function; 182 | break; 183 | } 184 | } 185 | 186 | if (result != NULL) { 187 | Dart_ExitScope(); 188 | return result; 189 | } 190 | 191 | Dart_ExitScope(); 192 | return result; 193 | } 194 | 195 | DART_EXPORT Dart_Handle dart_mssql_Init(Dart_Handle library) { 196 | 197 | // This should have to be CoUnitialized somewhere. Perhaps when Dart provides a "Done" hook? 198 | CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); 199 | 200 | if (Dart_IsError(library)) { 201 | return library; 202 | } 203 | Dart_Handle result = Dart_SetNativeResolver(library, nativeResolver, NULL); 204 | if (Dart_IsError(result)) { 205 | return result; 206 | } 207 | 208 | return Dart_Null(); 209 | } 210 | 211 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //ROUNDUP on all platforms pointers must be aligned properly 4 | constexpr auto ROUNDUP_AMOUNT = 8; 5 | #define ROUNDUP_(size,amount) (((DBBYTEOFFSET)(size)+((amount)-1))&~((DBBYTEOFFSET)(amount)-1)) 6 | #define ROUNDUP(size) ROUNDUP_(size, ROUNDUP_AMOUNT) 7 | 8 | Dart_Handle HandleError(Dart_Handle handle); 9 | 10 | BSTR UTF8ToBSTR(const char* utf8Value); 11 | 12 | char* WideCharToUTF8(const wchar_t* value); 13 | 14 | BSTR intToBSTR(int number); 15 | 16 | void addError(int* errorCount, std::string* errorMessages, const std::string errorMessage); 17 | 18 | HRESULT oleCheck(HRESULT hr, IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, int* errorCount, std::string* errorMessages); 19 | 20 | void DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, int* errorCount, std::string* errorMessages); 21 | 22 | HRESULT memoryCheck(HRESULT hr, void *pv, int* errorCount, std::string* errorMessages); 23 | 24 | HRESULT createShortDataAccessor(IUnknown* pUnkRowset, HACCESSOR* phAccessor, DBORDINAL* pcBindings, DBBINDING** prgBindings, DBORDINAL cColumns, DBCOLUMNINFO *rgColumnInfo, DBORDINAL* pcbRowSize, int* errorCount, std::string* errorMessages); 25 | 26 | HRESULT createLargeDataAcessors(IUnknown* pUnkRowset, HACCESSOR** phAccessors, DBORDINAL* pcBindings, DBBINDING** prgBindings, DBORDINAL cColumns, DBCOLUMNINFO *rgColumnInfo, int* errorCount, std::string* errorMessages); 27 | 28 | HRESULT createParamsAccessor(IUnknown* pUnkRowset, HACCESSOR* phAccessor, DBCOUNTITEM sqlParamsCount, Dart_Handle sqlParams, DBORDINAL* pcbRowSize, void** ppParamData, int* errorCount, std::string* errorMessages); 29 | 30 | void freeBindings(DBORDINAL cBindings, DBBINDING *rgBindings); 31 | 32 | HRESULT sqlConnect(const char* serverName, const char* dbName, const char* userName, const char* password, int64_t authType, IDBInitialize** ppInitialize, int* errorCount, std::string* errorMessages); 33 | 34 | void sqlExecute(IDBInitialize* pInitialize, const LPCOLESTR sqlCommand, Dart_Handle sqlParams, Dart_Handle dartMssqlLib, Dart_Handle dartSqlResult, int* errorCount, std::string* errorMessages); 35 | 36 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | IsolateTests 10 | Win32 11 | 12 | 13 | IsolateTests 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 15.0 31 | {D9A13674-7FA5-47D4-8E78-64C75166B926} 32 | Win32Proj 33 | dartmssql 34 | 10.0.17763.0 35 | 36 | 37 | 38 | DynamicLibrary 39 | true 40 | v141 41 | Unicode 42 | false 43 | 44 | 45 | DynamicLibrary 46 | true 47 | v141 48 | Unicode 49 | false 50 | 51 | 52 | DynamicLibrary 53 | false 54 | v141 55 | true 56 | Unicode 57 | 58 | 59 | DynamicLibrary 60 | true 61 | v141 62 | Unicode 63 | false 64 | 65 | 66 | DynamicLibrary 67 | true 68 | v141 69 | Unicode 70 | false 71 | 72 | 73 | DynamicLibrary 74 | false 75 | v141 76 | true 77 | Unicode 78 | false 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | true 106 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDK32\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\182\SDK\Include;..\dart_mssql 107 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;F:\DartSDK\dart-sdk\bin 108 | $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); 109 | 110 | 111 | true 112 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDKDebug\sdk\tools\sdks\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\181\SDK\Include;..\dart_mssql 113 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;F:\DartSDKDebug\sdk\tools\sdks\dart-sdk\bin 114 | $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); 115 | 116 | 117 | true 118 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDK64\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\182\SDK\Include 119 | $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;F:\DartSDK64\dart-sdk\bin 120 | $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\System32;$(FxCopDir);$(PATH); 121 | $(SolutionDir)$(Platform)\$(Configuration)\ 122 | false 123 | 124 | 125 | true 126 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDK64\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\181\SDK\Include 127 | $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;F:\DartSDK64\dart-sdk\bin 128 | $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\System32;$(FxCopDir);$(PATH); 129 | $(SolutionDir)$(Platform)\$(Configuration)\ 130 | false 131 | 132 | 133 | false 134 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDK32\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\182\SDK\Include 135 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;F:\DartSDK\dart-sdk\bin 136 | $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); 137 | 138 | 139 | false 140 | $(VC_IncludePath);$(WindowsSDK_IncludePath);F:\DartSDK64\dart-sdk\include;C:\Program Files\Microsoft SQL Server\Client SDK\OLEDB\182\SDK\Include 141 | $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;F:\DartSDK64\dart-sdk\bin 142 | $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); 143 | 144 | 145 | 146 | NotUsing 147 | Level3 148 | Disabled 149 | true 150 | WIN32;_DEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 151 | true 152 | false 153 | 154 | 155 | Windows 156 | true 157 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDK32\dart-sdk\bin\dart.lib 158 | F:\flutter\polygonus_mobile\server\mobile_aqueduct\dart_mssql.dll 159 | 160 | 161 | 162 | 163 | NotUsing 164 | Level3 165 | Disabled 166 | true 167 | WIN32;_DEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 168 | true 169 | false 170 | 171 | 172 | Windows 173 | true 174 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDKDebug\sdk\tools\sdks\dart-sdk\bin\dart.lib 175 | F:\flutter\polygonus\server\dart_mssql\dart_mssql.dll 176 | 177 | 178 | 179 | 180 | NotUsing 181 | Level3 182 | Disabled 183 | true 184 | _DEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 185 | true 186 | false 187 | /Zc:twoPhase- %(AdditionalOptions) 188 | 189 | 190 | Windows 191 | true 192 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDK64\dart-sdk\bin\dart.lib 193 | F:\flutter\polygonus_mobile\server\mobile_aqueduct\dart_mssql.dll 194 | 195 | 196 | 197 | 198 | NotUsing 199 | Level3 200 | Disabled 201 | true 202 | _DEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 203 | true 204 | false 205 | /Zc:twoPhase- %(AdditionalOptions) 206 | 207 | 208 | Windows 209 | true 210 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDK64\dart-sdk\bin\dart.lib 211 | F:\flutter\polygonus\server\dart_mssql\dart_mssql.dll 212 | 213 | 214 | 215 | 216 | NotUsing 217 | Level3 218 | MaxSpeed 219 | true 220 | true 221 | true 222 | WIN32;NDEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 223 | true 224 | 225 | 226 | Windows 227 | true 228 | true 229 | true 230 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDK32\dart-sdk\bin\dart.lib 231 | F:\flutter\polygonus\server\dart_mssql\dart_mssql.dll 232 | 233 | 234 | 235 | 236 | NotUsing 237 | Level3 238 | MaxSpeed 239 | true 240 | true 241 | true 242 | NDEBUG;DARTMSSQL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);DART_SHARED_LIB 243 | true 244 | false 245 | 246 | 247 | Windows 248 | true 249 | true 250 | true 251 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);F:\DartSDK64\dart-sdk\bin\dart.lib 252 | F:\flutter\polygonus\server\dart_mssql\dart_mssql.dll 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | Create 267 | Create 268 | Create 269 | Create 270 | Create 271 | Create 272 | 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Mixed 5 | WindowsLocalDebugger 6 | F:\DartSDKDebug\sdk\out\DebugX64\dart.exe 7 | "--enable-asserts" "bin\main.dart" "192.168.0.101" "80" "SGEIMM" 8 | F:\flutter\polygonus_mobile\server\mobile_aqueduct 9 | 10 | 11 | Mixed 12 | WindowsLocalDebugger 13 | F:\DartSDK32\dart-sdk\bin\dart.exe 14 | "--enable-asserts" "example\main.dart" 15 | f:\flutter\polygonus\server\dart_mssql 16 | 17 | 18 | false 19 | WindowsLocalDebugger 20 | F:\DartSDKDebug\sdk\out\DebugIA32\dart.exe 21 | "--enable-asserts" "bin\main.dart" "192.168.0.101" "80" "SGEIMM" 22 | F:\flutter\polygonus_mobile\server\mobile_aqueduct 23 | 24 | 25 | false 26 | WindowsLocalDebugger 27 | F:\DartSDKDebug\sdk\out\DebugIA32\dart.exe 28 | "--enable-asserts" "bin\main.dart" 29 | f:\flutter\polygonus\server\dart_mssql 30 | 31 | 32 | f:\flutter\polygonus\server\dart_mssql 33 | WindowsLocalDebugger 34 | 35 | 36 | f:\flutter\polygonus\server\dart_mssql 37 | WindowsLocalDebugger 38 | 39 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql_common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "stdafx.h" 6 | #include "msoledbsql.h" 7 | #include "dart_api.h" 8 | #include "dart_native_api.h" 9 | #include "dart_mssql.h" 10 | 11 | BSTR intToBSTR(int number) { 12 | wchar_t buf[32]; 13 | int len = swprintf(buf, 32, L"%d", number); 14 | BSTR result = SysAllocStringLen(buf, len); 15 | return result; 16 | } 17 | 18 | void addError(int* errorCount, std::string* errorMessages, std::string errorMessage) { 19 | (*errorMessages).append(errorMessage); 20 | (*errorCount)++; 21 | } 22 | 23 | BSTR UTF8ToBSTR(const char* utf8Value) { 24 | int wslen = MultiByteToWideChar(CP_UTF8, 0, utf8Value, (int)strlen(utf8Value), 0, 0); 25 | BSTR result = SysAllocStringLen(0, wslen); 26 | MultiByteToWideChar(CP_UTF8, 0, utf8Value, (int)strlen(utf8Value), result, wslen); 27 | return result; 28 | } 29 | 30 | char* WideCharToUTF8(const wchar_t* value) { 31 | if (value == NULL) { 32 | return NULL; 33 | } 34 | int n = WideCharToMultiByte(CP_UTF8, 0, value, -1, NULL, 0, NULL, NULL); 35 | if (n <= 0) { 36 | return NULL; 37 | } 38 | char* buffer = new char[n]; 39 | WideCharToMultiByte(CP_UTF8, 0, value, -1, buffer, n, NULL, NULL); 40 | return buffer; 41 | } 42 | 43 | // DumpErrorInfo queries MSOLEDBSQL error interfaces, retrieving available 44 | // status or error information. 45 | void DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, int* errorCount, std::string* errorMessages) 46 | { 47 | 48 | // Interfaces used in the example. 49 | IErrorInfo* pIErrorInfoAll = NULL; 50 | IErrorInfo* pIErrorInfoRecord = NULL; 51 | IErrorRecords* pIErrorRecords = NULL; 52 | ISupportErrorInfo* pISupportErrorInfo = NULL; 53 | ISQLErrorInfo* pISQLErrorInfo = NULL; 54 | ISQLServerErrorInfo* pISQLServerErrorInfo = NULL; 55 | 56 | // Number of error records. 57 | ULONG nRecs; 58 | ULONG nRec; 59 | 60 | // Basic error information from GetBasicErrorInfo. 61 | ERRORINFO errorinfo; 62 | 63 | // IErrorInfo values. 64 | BSTR bstrDescription; 65 | BSTR bstrSource; 66 | 67 | // ISQLErrorInfo parameters. 68 | BSTR bstrSQLSTATE; 69 | LONG lNativeError; 70 | 71 | // ISQLServerErrorInfo parameter pointers. 72 | SSERRORINFO* pSSErrorInfo = NULL; 73 | OLECHAR* pSSErrorStrings = NULL; 74 | 75 | // Hard-code an American English locale for the example. 76 | DWORD MYLOCALEID = 0x0409; 77 | 78 | // printing current date and time (moacir): 79 | time_t t = time(NULL); 80 | char strTime[26]; 81 | 82 | ctime_s(strTime, sizeof strTime, &t); 83 | fprintf_s(stderr, "Date/Time:\t%s", strTime); 84 | 85 | // Only ask for error information if the interface supports 86 | // it. 87 | if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo, 88 | (void**)&pISupportErrorInfo))) 89 | { 90 | fwprintf_s(stderr, L"SupportErrorErrorInfo interface not supported"); 91 | return; 92 | } 93 | if (FAILED(pISupportErrorInfo-> 94 | InterfaceSupportsErrorInfo(IID_InterfaceWithError))) 95 | { 96 | fwprintf_s(stderr, L"InterfaceWithError interface not supported"); 97 | return; 98 | } 99 | 100 | // Do not test the return of GetErrorInfo. It can succeed and return 101 | // a NULL pointer in pIErrorInfoAll. Simply test the pointer. 102 | GetErrorInfo(0, &pIErrorInfoAll); 103 | 104 | if (pIErrorInfoAll != NULL) 105 | { 106 | // Test to see if it's a valid OLE DB IErrorInfo interface 107 | // exposing a list of records. 108 | if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords, 109 | (void**)&pIErrorRecords))) 110 | { 111 | pIErrorRecords->GetRecordCount(&nRecs); 112 | 113 | // Within each record, retrieve information from each 114 | // of the defined interfaces. 115 | for (nRec = 0; nRec < nRecs; nRec++) 116 | { 117 | // From IErrorRecords, get the HRESULT and a reference 118 | // to the ISQLErrorInfo interface. 119 | pIErrorRecords->GetBasicErrorInfo(nRec, &errorinfo); 120 | pIErrorRecords->GetCustomErrorObject(nRec, 121 | IID_ISQLErrorInfo, (IUnknown**)&pISQLErrorInfo); 122 | 123 | // Display the HRESULT, then use the ISQLErrorInfo. 124 | fwprintf_s(stderr, L"HRESULT:\t%#X\n", errorinfo.hrError); 125 | 126 | if (pISQLErrorInfo != NULL) 127 | { 128 | pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE, 129 | &lNativeError); 130 | 131 | // Display the SQLSTATE and native error values. 132 | fwprintf_s(stderr, L"SQLSTATE:\t%s\nNative Error:\t%ld\n", bstrSQLSTATE, lNativeError); 133 | 134 | // SysFree BSTR references. 135 | SysFreeString(bstrSQLSTATE); 136 | 137 | // Get the ISQLServerErrorInfo interface from 138 | // ISQLErrorInfo before releasing the reference. 139 | pISQLErrorInfo->QueryInterface( 140 | IID_ISQLServerErrorInfo, 141 | (void**)&pISQLServerErrorInfo); 142 | 143 | pISQLErrorInfo->Release(); 144 | } 145 | 146 | // Test to ensure the reference is valid, then 147 | // get error information from ISQLServerErrorInfo. 148 | if (pISQLServerErrorInfo != NULL) 149 | { 150 | pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo, 151 | &pSSErrorStrings); 152 | 153 | // ISQLServerErrorInfo::GetErrorInfo succeeds 154 | // even when it has nothing to return. Test the 155 | // pointers before using. 156 | if (pSSErrorInfo) 157 | { 158 | // Display the state and severity from the 159 | // returned information. The error message comes 160 | // from IErrorInfo::GetDescription. 161 | fwprintf_s(stderr, L"Error state:\t%d\nSeverity:\t%d\n", pSSErrorInfo->bState, pSSErrorInfo->bClass); 162 | 163 | // IMalloc::Free needed to release references 164 | // on returned values. For the example, assume 165 | // the g_pIMalloc pointer is valid. 166 | // Moacir: Troquei pra CoTaskMemFree pq nao achei lib de g_pIMalloc 167 | CoTaskMemFree(pSSErrorStrings); 168 | CoTaskMemFree(pSSErrorInfo); 169 | } 170 | 171 | pISQLServerErrorInfo->Release(); 172 | } 173 | 174 | if (SUCCEEDED(pIErrorRecords->GetErrorInfo(nRec, 175 | MYLOCALEID, &pIErrorInfoRecord))) 176 | { 177 | // Get the source and description (error message) 178 | // from the record's IErrorInfo. 179 | pIErrorInfoRecord->GetSource(&bstrSource); 180 | pIErrorInfoRecord->GetDescription(&bstrDescription); 181 | 182 | if (bstrSource != NULL) 183 | { 184 | fwprintf_s(stderr, L"Source:\t\t%s\n", bstrSource); 185 | SysFreeString(bstrSource); 186 | } 187 | if (bstrDescription != NULL) 188 | { 189 | fwprintf_s(stderr, L"Error message:\t%s\n", bstrDescription); 190 | SysFreeString(bstrDescription); 191 | } 192 | 193 | pIErrorInfoRecord->Release(); 194 | } 195 | } 196 | 197 | pIErrorRecords->Release(); 198 | } 199 | else 200 | { 201 | // IErrorInfo is valid; get the source and 202 | // description to see what it is. 203 | pIErrorInfoAll->GetSource(&bstrSource); 204 | pIErrorInfoAll->GetDescription(&bstrDescription); 205 | 206 | if (bstrSource != NULL) 207 | { 208 | fwprintf_s(stderr, L"Source:\t\t%s\n", bstrSource); 209 | SysFreeString(bstrSource); 210 | } 211 | if (bstrDescription != NULL) 212 | { 213 | fwprintf_s(stderr, L"Error message:\t%s\n", bstrDescription); 214 | SysFreeString(bstrDescription); 215 | } 216 | } 217 | 218 | pIErrorInfoAll->Release(); 219 | } 220 | else 221 | { 222 | fwprintf_s(stderr, L"GetErrorInfo failed."); 223 | } 224 | 225 | pISupportErrorInfo->Release(); 226 | 227 | return; 228 | } 229 | 230 | HRESULT oleCheck(HRESULT hr, IUnknown* pObjectWithError, REFIID IID_InterfaceWithError, int* errorCount, std::string* errorMessages) { 231 | if (FAILED(hr) && pObjectWithError != NULL) { 232 | DumpErrorInfo(pObjectWithError, IID_InterfaceWithError, errorCount, errorMessages); 233 | } 234 | // fill errorMessages if last operation had a error 235 | if (FAILED(hr) && errorCount != NULL) { 236 | IErrorInfo *pIErrorInfo = NULL; 237 | IErrorRecords *pIErrorRecords; 238 | 239 | (*errorMessages).assign(""); 240 | GetErrorInfo(0, &pIErrorInfo); 241 | if (pIErrorInfo != NULL && *errorCount == 0) { 242 | HRESULT hr1 = pIErrorInfo->QueryInterface(IID_IErrorRecords, (void **)&pIErrorRecords); 243 | if (SUCCEEDED(hr1)) { 244 | ULONG pcRecords; 245 | pIErrorRecords->GetRecordCount(&pcRecords); 246 | *errorCount = pcRecords; 247 | boolean ok = FALSE; 248 | for (ULONG i = 0; i < pcRecords; i++) { 249 | ISQLServerErrorInfo *pISQLServerErrorInfo; 250 | pIErrorRecords->GetCustomErrorObject( 251 | i, IID_ISQLServerErrorInfo, 252 | (IUnknown**)&pISQLServerErrorInfo); 253 | ok = (pISQLServerErrorInfo > 0); 254 | if (ok) { 255 | SSERRORINFO *errorInfo; 256 | OLECHAR *errorMsgs; 257 | pISQLServerErrorInfo->GetErrorInfo(&errorInfo, &errorMsgs); 258 | ok = (errorInfo != NULL); 259 | if (ok) { 260 | (*errorMessages).append(WideCharToUTF8(errorMsgs)); 261 | CoTaskMemFree(errorInfo); 262 | CoTaskMemFree(errorMsgs); 263 | } 264 | pISQLServerErrorInfo->Release(); 265 | } 266 | if (!ok) { 267 | OLECHAR *errorMsgs; 268 | pIErrorRecords->GetErrorInfo(i, 0, &pIErrorInfo); 269 | pIErrorInfo->GetDescription(&errorMsgs); 270 | ok = (errorMsgs != NULL); 271 | if (ok) { 272 | (*errorMessages).append(WideCharToUTF8(errorMsgs)); 273 | pIErrorInfo->Release(); 274 | SysFreeString(errorMsgs); 275 | } 276 | } 277 | } 278 | pIErrorRecords->Release(); 279 | } 280 | } 281 | if ((*errorMessages).length() == 0) { 282 | char errorBuf[32]; 283 | int len = snprintf(errorBuf, 32, "error code: 0x%X\0", hr); 284 | addError(errorCount, errorMessages, errorBuf); 285 | } 286 | if (pIErrorInfo != NULL) { 287 | pIErrorInfo->Release(); 288 | } 289 | } 290 | return hr; 291 | } 292 | 293 | HRESULT memoryCheck(HRESULT hr, void *pv, int* errorCount, std::string* errorMessages) { 294 | if (!pv) { 295 | hr = E_OUTOFMEMORY; 296 | return oleCheck(hr, NULL, GUID_NULL, errorCount, errorMessages); 297 | } 298 | else { 299 | return hr; 300 | } 301 | } 302 | 303 | ///////////////////////////////////////////////////////////////// 304 | // freeBindings 305 | // 306 | // This function frees a bindings array and any allocated 307 | // structures contained in that array. 308 | // 309 | ///////////////////////////////////////////////////////////////// 310 | void freeBindings(DBORDINAL cBindings, DBBINDING* rgBindings) { 311 | ULONG iBind; 312 | 313 | // Free any memory used by DBOBJECT structures in the array 314 | for (iBind = 0; iBind < cBindings; iBind++) 315 | CoTaskMemFree(rgBindings[iBind].pObject); 316 | 317 | // Now free the bindings array itself 318 | CoTaskMemFree(rgBindings); 319 | } 320 | 321 | ///////////////////////////////////////////////////////////////// 322 | // getProperty 323 | // 324 | // This function gets the BOOL value for the specified property 325 | // and returns the result in *pbValue. 326 | // 327 | // here we do not pass errorCount and errorMessages since errors are expected for non-supported properties 328 | ///////////////////////////////////////////////////////////////// 329 | HRESULT getProperty(IUnknown* pIUnknown, REFIID riid, DBPROPID dwPropertyID, REFGUID guidPropertySet, BOOL* pbValue) { 330 | HRESULT hr; 331 | DBPROPID rgPropertyIDs[1]; 332 | DBPROPIDSET rgPropertyIDSets[1]; 333 | 334 | ULONG cPropSets = 0; 335 | DBPROPSET* rgPropSets = NULL; 336 | 337 | IDBProperties* pIDBProperties = NULL; 338 | ISessionProperties* pISesProps = NULL; 339 | ICommandProperties* pICmdProps = NULL; 340 | IRowsetInfo* pIRowsetInfo = NULL; 341 | 342 | // Initialize the output value 343 | *pbValue = FALSE; 344 | 345 | // Set up the property ID array 346 | rgPropertyIDs[0] = dwPropertyID; 347 | 348 | // Set up the Property ID Set 349 | rgPropertyIDSets[0].rgPropertyIDs = rgPropertyIDs; 350 | rgPropertyIDSets[0].cPropertyIDs = 1; 351 | rgPropertyIDSets[0].guidPropertySet = guidPropertySet; 352 | 353 | // Get the property value for this property from the provider, but 354 | // don't try to display extended error information, since this may 355 | // not be a supported property: a failure is, in fact, expected if 356 | // the property is not supported 357 | if (riid == IID_IDBProperties) { 358 | hr = pIUnknown->QueryInterface(IID_IDBProperties, 359 | (void**)&pIDBProperties); 360 | if (oleCheck(hr, pIDBProperties, IID_IDBProperties, NULL, NULL) < 0) goto CLEANUP; 361 | hr = pIDBProperties->GetProperties( 362 | 1, //cPropertyIDSets 363 | rgPropertyIDSets, //rgPropertyIDSets 364 | &cPropSets, //pcPropSets 365 | &rgPropSets //prgPropSets); 366 | ); 367 | if (oleCheck(hr, pIDBProperties, IID_IDBProperties, NULL, NULL) < 0) goto CLEANUP; 368 | } 369 | else if (riid == IID_ISessionProperties) { 370 | hr = pIUnknown->QueryInterface(IID_ISessionProperties, 371 | (void**)&pISesProps); 372 | if (oleCheck(hr, pISesProps, IID_ISessionProperties, NULL, NULL) < 0) goto CLEANUP; 373 | hr = pISesProps->GetProperties( 374 | 1, //cPropertyIDSets 375 | rgPropertyIDSets, //rgPropertyIDSets 376 | &cPropSets, //pcPropSets 377 | &rgPropSets //prgPropSets 378 | ); 379 | if (oleCheck(hr, pISesProps, IID_ISessionProperties, NULL, NULL) < 0) goto CLEANUP; 380 | } 381 | else if (riid == IID_ICommandProperties) { 382 | hr = pIUnknown->QueryInterface(IID_ICommandProperties, 383 | (void**)&pICmdProps); 384 | if (oleCheck(hr, pICmdProps, IID_ICommandProperties, NULL, NULL) < 0) goto CLEANUP; 385 | hr = pICmdProps->GetProperties( 386 | 1, //cPropertyIDSets 387 | rgPropertyIDSets, //rgPropertyIDSets 388 | &cPropSets, //pcPropSets 389 | &rgPropSets //prgPropSets 390 | ); 391 | if (oleCheck(hr, pICmdProps, IID_ICommandProperties, NULL, NULL) < 0) goto CLEANUP; 392 | } 393 | else { 394 | hr = pIUnknown->QueryInterface(IID_IRowsetInfo, 395 | (void**)&pIRowsetInfo); 396 | if (oleCheck(hr, pIRowsetInfo, IID_IRowsetInfo, NULL, NULL) < 0) goto CLEANUP; 397 | hr = pIRowsetInfo->GetProperties( 398 | 1, //cPropertyIDSets 399 | rgPropertyIDSets, //rgPropertyIDSets 400 | &cPropSets, //pcPropSets 401 | &rgPropSets //prgPropSets 402 | ); 403 | if (oleCheck(hr, pIRowsetInfo, IID_IRowsetInfo, NULL, NULL) < 0) goto CLEANUP; 404 | } 405 | 406 | // Return the value for this property to the caller if 407 | // it's a VT_BOOL type value, as expected 408 | if (V_VT(&rgPropSets[0].rgProperties[0].vValue) == VT_BOOL) 409 | *pbValue = V_BOOL(&rgPropSets[0].rgProperties[0].vValue); 410 | 411 | CLEANUP: 412 | if (rgPropSets) { 413 | CoTaskMemFree(rgPropSets[0].rgProperties); 414 | CoTaskMemFree(rgPropSets); 415 | } 416 | if (pIDBProperties) 417 | pIDBProperties->Release(); 418 | if (pISesProps) 419 | pISesProps->Release(); 420 | if (pICmdProps) 421 | pICmdProps->Release(); 422 | if (pIRowsetInfo) 423 | pIRowsetInfo->Release(); 424 | return hr; 425 | } 426 | 427 | HRESULT createShortDataAccessor(IUnknown* pUnkRowset, HACCESSOR* phAccessor, DBORDINAL* pcBindings, DBBINDING** prgBindings, DBORDINAL cColumns, DBCOLUMNINFO *rgColumnInfo, DBORDINAL* pcbRowSize, int* errorCount, std::string* errorMessages) { 428 | HRESULT hr = NULL; 429 | IAccessor* pIAccessor = NULL; 430 | DBLENGTH iCol; 431 | DBORDINAL dwOffset = 0; 432 | DBBINDING* rgBindings = NULL; 433 | 434 | // Getting short data count 435 | int iShortCol = 0; 436 | for (iCol = 0; iCol < cColumns; iCol++) { 437 | // Only short Data! 438 | if (rgColumnInfo[iCol].wType != DBTYPE_IUNKNOWN && (rgColumnInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISLONG) == 0) 439 | iShortCol++; 440 | } 441 | 442 | // Allocate memory for the bindings array; there is a one-to-one 443 | // mapping between the columns returned from GetColumnInfo and our 444 | // bindings 445 | if (iShortCol > 0) { 446 | rgBindings = (DBBINDING*)CoTaskMemAlloc(iShortCol * sizeof(DBBINDING)); 447 | if (memoryCheck(hr, rgBindings, errorCount, errorMessages) < 0) goto CLEANUP; 448 | memset(rgBindings, 0, iShortCol * sizeof(DBBINDING)); 449 | 450 | // Construct the binding array element for each column 451 | iShortCol = 0; 452 | for (iCol = 0; iCol < cColumns; iCol++) { 453 | if (rgColumnInfo[iCol].wType != DBTYPE_IUNKNOWN && (rgColumnInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISLONG) == 0) { 454 | // This binding applies to the ordinal of this column 455 | rgBindings[iShortCol].iOrdinal = rgColumnInfo[iCol].iOrdinal; 456 | 457 | // We are asking the provider to give us the data for this column 458 | // (DBPART_VALUE), the length of that data (DBPART_LENGTH), and 459 | // the status of the column (DBPART_STATUS) 460 | rgBindings[iShortCol].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS; 461 | 462 | // The following values are the offsets to the status, length, and 463 | // data value that the provider will fill with the appropriate values 464 | // when we fetch data later. When we fetch data, we will pass a 465 | // pointer to a buffer that the provider will copy column data to, 466 | // in accordance with the binding we have provided for that column; 467 | // these are offsets into that future buffer 468 | rgBindings[iShortCol].obStatus = dwOffset; 469 | rgBindings[iShortCol].obLength = dwOffset + sizeof(DBSTATUS); 470 | rgBindings[iShortCol].obValue = dwOffset + sizeof(DBSTATUS) + sizeof(DBORDINAL); 471 | rgBindings[iShortCol].pTypeInfo = NULL; 472 | rgBindings[iShortCol].pBindExt = NULL; 473 | rgBindings[iShortCol].pObject = NULL; 474 | rgBindings[iShortCol].dwFlags = 0; 475 | 476 | // Any memory allocated for the data value will be owned by us, the 477 | // client. Note that no data will be allocated in this case, as the 478 | // DBTYPE_WSTR bindings we are using will tell the provider to simply 479 | // copy data directly into our provided buffer 480 | rgBindings[iShortCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED; 481 | 482 | // This is not a parameter binding 483 | rgBindings[iShortCol].eParamIO = DBPARAMIO_NOTPARAM; 484 | 485 | // We want to use the precision and scale of the column 486 | rgBindings[iShortCol].bPrecision = rgColumnInfo[iCol].bPrecision; 487 | rgBindings[iShortCol].bScale = rgColumnInfo[iCol].bScale; 488 | 489 | // Bind this column as DBTYPE_WSTR, which tells the provider to 490 | // copy a Unicode string representation of the data into our buffer, 491 | // converting from the native type if necessary 492 | rgBindings[iShortCol].wType = DBTYPE_WSTR; 493 | 494 | // Initially, we set the length for this data in our buffer to 0; 495 | // the correct value for this will be calculated directly below 496 | rgBindings[iShortCol].cbMaxLen = 0; 497 | 498 | // Determine the maximum number of bytes required in our buffer to 499 | // contain the Unicode string representation of the provider's native 500 | // data type, including room for the NULL-termination character 501 | switch (rgColumnInfo[iCol].wType) 502 | { 503 | case DBTYPE_NULL: 504 | case DBTYPE_EMPTY: 505 | case DBTYPE_I1: 506 | case DBTYPE_I2: 507 | case DBTYPE_I4: 508 | case DBTYPE_UI1: 509 | case DBTYPE_UI2: 510 | case DBTYPE_UI4: 511 | case DBTYPE_R4: 512 | case DBTYPE_BOOL: 513 | case DBTYPE_I8: 514 | case DBTYPE_UI8: 515 | case DBTYPE_R8: 516 | case DBTYPE_CY: 517 | case DBTYPE_ERROR: 518 | // When the above types are converted to a string, they 519 | // will all fit into 25 characters, so use that plus space 520 | // for the NULL-terminator 521 | rgBindings[iShortCol].cbMaxLen = (25 + 1) * sizeof(WCHAR); 522 | break; 523 | 524 | case DBTYPE_DECIMAL: 525 | case DBTYPE_NUMERIC: 526 | case DBTYPE_DATE: 527 | case DBTYPE_DBDATE: 528 | case DBTYPE_DBTIMESTAMP: 529 | case DBTYPE_GUID: 530 | // Converted to a string, the above types will all fit into 531 | // 50 characters, so use that plus space for the terminator 532 | rgBindings[iShortCol].cbMaxLen = (50 + 1) * sizeof(WCHAR); 533 | break; 534 | 535 | case DBTYPE_BYTES: 536 | // In converting DBTYPE_BYTES to a string, each byte 537 | // becomes two characters (e.g. 0xFF -> "FF"), so we 538 | // will use double the maximum size of the column plus 539 | // include space for the NULL-terminator 540 | rgBindings[iShortCol].cbMaxLen = 541 | (rgColumnInfo[iCol].ulColumnSize * 2 + 1) * sizeof(WCHAR); 542 | break; 543 | 544 | case DBTYPE_STR: 545 | case DBTYPE_WSTR: 546 | case DBTYPE_BSTR: 547 | // Going from a string to our string representation, 548 | // we can just take the maximum size of the column, 549 | // a count of characters, and include space for the 550 | // terminator, which is not included in the column size 551 | rgBindings[iShortCol].cbMaxLen = 552 | (rgColumnInfo[iCol].ulColumnSize + 1) * sizeof(WCHAR); 553 | break; 554 | 555 | default: 556 | // For any other type, we will simply use our maximum 557 | // column buffer size, since the display size of these 558 | // columns may be variable (e.g. DBTYPE_VARIANT) or 559 | // unknown (e.g. provider-specific types) 560 | if (*errorCount == 0) { 561 | addError(errorCount, errorMessages, "Unknown data type"); 562 | hr = -1; 563 | } 564 | break; 565 | }; 566 | 567 | // Ensure that the bound maximum length is no more than the 568 | // maximum column size in bytes that we've defined 569 | // (comentado por moacir. Prefiro pegar tudo!) rgBindings[iCol].cbMaxLen = min(rgBindings[iCol].cbMaxLen, maxColSize); 570 | 571 | // Update the offset past the end of this column's data, so 572 | // that the next column will begin in the correct place in 573 | // the buffer 574 | dwOffset = rgBindings[iShortCol].cbMaxLen + rgBindings[iShortCol].obValue; 575 | 576 | // Ensure that the data for the next column will be correctly 577 | // aligned for all platforms, or, if we're done with columns, 578 | // that if we allocate space for multiple rows that the data 579 | // for every row is correctly aligned 580 | dwOffset = ROUNDUP(dwOffset); 581 | iShortCol++; 582 | } 583 | } 584 | 585 | // Now that we have an array of bindings, tell the provider to 586 | // create the Accessor for those bindings. We get back a handle 587 | // to this Accessor, which we will use when fetching data 588 | hr = pUnkRowset->QueryInterface( 589 | IID_IAccessor, (void**)&pIAccessor); 590 | if (oleCheck(hr, pIAccessor, IID_IAccessor, errorCount, errorMessages) < 0) goto CLEANUP; 591 | hr = pIAccessor->CreateAccessor( 592 | DBACCESSOR_ROWDATA, //dwAccessorFlags 593 | iShortCol, //cBindings 594 | rgBindings, //rgBindings 595 | 0, //cbRowSize 596 | phAccessor, //phAccessor 597 | NULL //rgStatus 598 | ); 599 | if (oleCheck(hr, pIAccessor, IID_IAccessor, errorCount, errorMessages) < 0) goto CLEANUP; 600 | } 601 | 602 | // Return the row size (the current dwOffset is the size of the row), 603 | // the count of bindings, and the bindings array to the caller 604 | *pcbRowSize = dwOffset; 605 | *pcBindings = iShortCol; 606 | *prgBindings = rgBindings; 607 | 608 | CLEANUP: 609 | if (pIAccessor) 610 | pIAccessor->Release(); 611 | return hr; 612 | } 613 | 614 | HRESULT createLargeDataAcessors(IUnknown* pUnkRowset, HACCESSOR** phAccessors, DBORDINAL* pcBindings, DBBINDING** prgBindings, DBORDINAL cColumns, DBCOLUMNINFO *rgColumnInfo, int* errorCount, std::string* errorMessages) { 615 | HRESULT hr = NULL; 616 | DBLENGTH iCol; 617 | DBBINDING* rgBindings = NULL; 618 | IAccessor* pIAccessor = NULL; 619 | HACCESSOR hAccessor; 620 | ULONG ulbindstatus; 621 | int iLargeCol = 0; 622 | 623 | 624 | *phAccessors = NULL; 625 | 626 | // Getting large data count 627 | for (iCol = 0; iCol < cColumns; iCol++) { 628 | // Only short Data! 629 | if (rgColumnInfo[iCol].wType == DBTYPE_IUNKNOWN || (rgColumnInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISLONG) != 0) 630 | iLargeCol++; 631 | } 632 | 633 | // Allocate memory for the bindings array; there is a one-to-one 634 | // mapping between the columns returned from GetColumnInfo and our 635 | // bindings 636 | if (iLargeCol > 0) { 637 | rgBindings = (DBBINDING*)CoTaskMemAlloc(iLargeCol * sizeof(DBBINDING)); 638 | if (memoryCheck(hr, rgBindings, errorCount, errorMessages) < 0) goto CLEANUP; 639 | memset(rgBindings, 0, iLargeCol * sizeof(DBBINDING)); 640 | 641 | // Construct the binding array element for each column 642 | iLargeCol = 0; 643 | for (iCol = 0; iCol < cColumns; iCol++) { 644 | if (rgColumnInfo[iCol].wType == DBTYPE_IUNKNOWN || (rgColumnInfo[iCol].dwFlags & DBCOLUMNFLAGS_ISLONG) != 0) { 645 | // This binding applies to the ordinal of this column 646 | rgBindings[iLargeCol].iOrdinal = rgColumnInfo[iCol].iOrdinal; 647 | 648 | // We are asking the provider to give us the data for this column 649 | // (DBPART_VALUE) and the status of the column (DBPART_STATUS) 650 | rgBindings[iLargeCol].dwPart = DBPART_VALUE | DBPART_STATUS; 651 | 652 | // The following values are the offsets to the status, length, and 653 | // data value that the provider will fill with the appropriate values 654 | // when we fetch data later. When we fetch data, we will pass a 655 | // pointer to a buffer that the provider will copy column data to, 656 | // in accordance with the binding we have provided for that column; 657 | // these are offsets into that future buffer 658 | rgBindings[iLargeCol].obStatus = sizeof(IUnknown*); 659 | rgBindings[iLargeCol].obLength = 0; 660 | rgBindings[iLargeCol].obValue = 0; 661 | rgBindings[iLargeCol].pTypeInfo = NULL; 662 | rgBindings[iLargeCol].pBindExt = NULL; 663 | rgBindings[iLargeCol].dwFlags = 0; 664 | rgBindings[iLargeCol].bPrecision = 0; 665 | rgBindings[iLargeCol].bScale = 0; 666 | // To specify the type of object that we want from the 667 | // provider, we need to create a DBOBJECT structure and 668 | // place it in our binding for this column 669 | rgBindings[iLargeCol].pObject = 670 | (DBOBJECT *)CoTaskMemAlloc(sizeof(DBOBJECT)); 671 | if (memoryCheck(hr, rgBindings[iLargeCol].pObject, errorCount, errorMessages) < 0) goto CLEANUP; 672 | // Direct the provider to create an ISequentialStream 673 | // object over the data for this column 674 | rgBindings[iLargeCol].pObject->iid = IID_ISequentialStream; 675 | // We want read access on the ISequentialStream 676 | // object that the provider will create for us 677 | rgBindings[iLargeCol].pObject->dwFlags = STGM_READ; 678 | 679 | // Any memory allocated for the data value will be owned by us, the 680 | // client. Note that no data will be allocated in this case, as the 681 | // DBTYPE_WSTR bindings we are using will tell the provider to simply 682 | // copy data directly into our provided buffer 683 | rgBindings[iLargeCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED; 684 | 685 | // This is not a parameter binding 686 | rgBindings[iLargeCol].eParamIO = DBPARAMIO_NOTPARAM; 687 | 688 | // To create an ISequentialStream object, we will 689 | // bind this column as DBTYPE_IUNKNOWN to indicate 690 | // that we are requesting this column as an object 691 | rgBindings[iLargeCol].wType = DBTYPE_IUNKNOWN; 692 | 693 | // We want to allocate enough space in our buffer for 694 | // the ISequentialStream pointer we will obtain from 695 | // the provider 696 | rgBindings[iLargeCol].cbMaxLen = 0; 697 | 698 | // Ensure that the bound maximum length is no more than the 699 | // maximum column size in bytes that we've defined 700 | // (comentado por moacir. Prefiro pegar tudo!) rgBindings[iCol].cbMaxLen = min(rgBindings[iCol].cbMaxLen, maxColSize); 701 | 702 | // Now that we have an one bindings for lage object, tell the provider to 703 | // create the Accessor for this bindins. We get back a handle 704 | // to this Accessor, which we will use when fetching data 705 | hr = pUnkRowset->QueryInterface( 706 | IID_IAccessor, (void**)&pIAccessor); 707 | if (oleCheck(hr, pIAccessor, IID_IAccessor, errorCount, errorMessages) < 0) goto CLEANUP; 708 | hr = pIAccessor->CreateAccessor( 709 | DBACCESSOR_ROWDATA, //dwAccessorFlags 710 | 1, //cBindings 711 | &rgBindings[iLargeCol], //rgBindings 712 | 0, //cbRowSize 713 | &hAccessor, //phAccessor 714 | &ulbindstatus //rgStatus 715 | ); 716 | *phAccessors = (HACCESSOR*)CoTaskMemRealloc(*phAccessors, (iLargeCol + 1) * sizeof(HACCESSOR)); 717 | if (memoryCheck(hr, *phAccessors, errorCount, errorMessages) < 0) goto CLEANUP; 718 | 719 | (*phAccessors)[iLargeCol] = hAccessor; 720 | if (pIAccessor) 721 | pIAccessor->Release(); 722 | 723 | iLargeCol++; 724 | } 725 | } 726 | } 727 | *pcBindings = iLargeCol; 728 | *prgBindings = rgBindings; 729 | 730 | CLEANUP: 731 | return hr; 732 | } 733 | 734 | HRESULT createParamsAccessor(IUnknown* pUnkRowset, HACCESSOR* phAccessor, DBCOUNTITEM sqlParamsCount, Dart_Handle sqlParams, DBORDINAL* pcbRowSize, void** ppParamData, int* errorCount, std::string* errorMessages) { 735 | HRESULT hr = NULL; 736 | IAccessor* pIAccessor = NULL; 737 | DBCOUNTITEM iCol; 738 | DBORDINAL dwOffset = 0, lastOffset = 0; 739 | DBBINDING* rgBindings = NULL; 740 | void* pParamData = NULL; 741 | void* pCurParam = NULL; 742 | void* pSourceValue = NULL; 743 | 744 | // Allocate memory for the bindings array; there is a one-to-one 745 | // mapping between the columns returned from GetColumnInfo and our 746 | // bindings 747 | rgBindings = (DBBINDING*)CoTaskMemAlloc(sqlParamsCount * sizeof(DBBINDING)); 748 | if (memoryCheck(hr, rgBindings, errorCount, errorMessages) < 0) goto CLEANUP; 749 | memset(rgBindings, 0, sqlParamsCount * sizeof(DBBINDING)); 750 | 751 | // Construct the binding array element for each param 752 | for (iCol = 0; iCol < sqlParamsCount; iCol++) { 753 | int64_t dartValueI64; 754 | const char* dartValueString; 755 | // This binding applies to the ordinal of this column 756 | rgBindings[iCol].iOrdinal = iCol+1; 757 | rgBindings[iCol].dwPart = DBPART_VALUE; 758 | rgBindings[iCol].obStatus = 0; 759 | rgBindings[iCol].obLength = 0; 760 | rgBindings[iCol].obValue = dwOffset; 761 | rgBindings[iCol].pTypeInfo = NULL; 762 | rgBindings[iCol].pBindExt = NULL; 763 | rgBindings[iCol].pObject = NULL; 764 | rgBindings[iCol].dwFlags = 0; 765 | rgBindings[iCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED; 766 | rgBindings[iCol].eParamIO = DBPARAMIO_INPUT; 767 | rgBindings[iCol].bPrecision = 0; 768 | rgBindings[iCol].bScale = 0; 769 | Dart_Handle item = Dart_Handle(Dart_ListGetAt(sqlParams, iCol)); 770 | if (Dart_IsNumber(item)) { 771 | HandleError(Dart_IntegerToInt64(item, &dartValueI64)); 772 | rgBindings[iCol].wType = DBTYPE_I4; 773 | rgBindings[iCol].cbMaxLen = sizeof(dartValueI64); 774 | pSourceValue = &dartValueI64; 775 | } 776 | else if (Dart_IsString(item)) { 777 | HandleError(Dart_StringToCString(item, &dartValueString)); 778 | rgBindings[iCol].wType = DBTYPE_STR; 779 | rgBindings[iCol].cbMaxLen = strlen(dartValueString); 780 | pSourceValue = (void*) dartValueString; 781 | } 782 | else { 783 | addError(errorCount, errorMessages, "Unknown param type"); 784 | } 785 | 786 | lastOffset = dwOffset; 787 | dwOffset = dwOffset + rgBindings[iCol].cbMaxLen; 788 | dwOffset = ROUNDUP(dwOffset); 789 | 790 | pParamData = CoTaskMemRealloc(pParamData, dwOffset); 791 | if (memoryCheck(hr, pParamData, errorCount, errorMessages) < 0) goto CLEANUP; 792 | 793 | void* pCurParam = (BYTE*)pParamData + lastOffset; 794 | memset(pCurParam, 0, dwOffset - lastOffset); 795 | memcpy((void*)pCurParam, pSourceValue, rgBindings[iCol].cbMaxLen); 796 | } 797 | 798 | // Now that we have an array of bindings, tell the provider to 799 | // create the Accessor for those bindings. We get back a handle 800 | // to this Accessor, which we will use when fetching data 801 | hr = pUnkRowset->QueryInterface( 802 | IID_IAccessor, (void**)&pIAccessor); 803 | if (oleCheck(hr, pIAccessor, IID_IAccessor, errorCount, errorMessages) < 0) goto CLEANUP; 804 | hr = pIAccessor->CreateAccessor( 805 | DBACCESSOR_PARAMETERDATA, //dwAccessorFlags 806 | sqlParamsCount, //cBindings 807 | rgBindings, //rgBindings 808 | dwOffset, //cbRowSize 809 | phAccessor, //phAccessor 810 | NULL //rgStatus 811 | ); 812 | if (oleCheck(hr, pIAccessor, IID_IAccessor, errorCount, errorMessages) < 0) goto CLEANUP; 813 | 814 | *pcbRowSize = dwOffset; 815 | *ppParamData = pParamData; 816 | 817 | CLEANUP: 818 | if (pIAccessor) 819 | pIAccessor->Release(); 820 | return hr; 821 | } 822 | 823 | -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql_connection.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/cpp/dart_mssql/dart_mssql_connection.cpp -------------------------------------------------------------------------------- /cpp/dart_mssql/dart_mssql_dllmain_win.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /cpp/dart_mssql/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /cpp/dart_mssql/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files 12 | #include 13 | 14 | 15 | 16 | // reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /cpp/dart_mssql/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /dart_mssql_32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/dart_mssql_32.dll -------------------------------------------------------------------------------- /dart_mssql_64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/dart_mssql_64.dll -------------------------------------------------------------------------------- /example/dart_mssql_32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/example/dart_mssql_32.dll -------------------------------------------------------------------------------- /example/dart_mssql_64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoacirSchmidt/dart_mssql/ef6f341aacf00d9c7c6e643b4013290f00a93494/example/dart_mssql_64.dll -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:dart_mssql/dart_mssql.dart'; 3 | 4 | // class "Client" for ORM example 5 | class Client { 6 | int client_id; 7 | String client_name; 8 | List invoices; 9 | 10 | Client.fromJson(Map json) { 11 | client_id = json['client_id']; 12 | client_name = json['client_name']; 13 | } 14 | 15 | Map toJson() { 16 | return { 17 | 'client_id': client_id, 18 | 'client_name': client_name, 19 | }; 20 | } 21 | } 22 | 23 | // class "Invoice" for ORM example 24 | class Invoice { 25 | int client_id; 26 | int inv_number; 27 | 28 | Invoice.fromJson(Map json) { 29 | client_id = json['client_id']; 30 | inv_number = json['inv_number']; 31 | } 32 | 33 | Map toJson() { 34 | return { 35 | 'client_id': client_id, 36 | 'inv_number': inv_number, 37 | }; 38 | } 39 | } 40 | 41 | void main() { 42 | // Establish a connection 43 | SqlConnection connection = SqlConnection(host:"SERVERNAME", db:"DBNAME", user:"USERNAME", password:"PASSWORD"); 44 | 45 | // Querying several rows 46 | String cmd = "select id_nacionalidade,nom_nacionalidade from nacionalidade where id_nacionalidade>?"; // parameters binding! 47 | SqlResult result = connection.execute(cmd,[4]); 48 | result.rows.forEach((e) { 49 | print("${e.id_nacionalidade}"); 50 | }); 51 | 52 | // Querying one row 53 | cmd = "select id_nacionalidade,nom_nacionalidade from nacionalidade where id_nacionalidade=?"; 54 | dynamic row = connection.selectOne(cmd,[4]); // "dynamic" var is important... 55 | print(row.id_nacionalidade); // ...to allow accessing fields by name 56 | 57 | // raw insert 58 | cmd = "insert into nacionalidade(id_nacionalidade,nom_nacionalidade) values (1, 'Brasileira')"; 59 | connection.execute(cmd); 60 | 61 | // raw update 62 | cmd = "update nacionalidade set nom_nacionalidade = 'Argentina' where id_nacionalidade=1"; 63 | connection.execute(cmd); 64 | 65 | // raw delete 66 | cmd = "delete from nacionalidade where id_nacionalidade=1"; 67 | connection.execute(cmd); 68 | 69 | // insert 70 | connection.insert("nacionalidade", {"id_nacionalidade": 1, "nom_nacionalidade": "Brasileira"}); 71 | 72 | // update 73 | connection.update("nacionalidade", {"nom_nacionalidade": "Argentina"}, "id_nacionalidade=?", [1]); 74 | 75 | // delete 76 | connection.delete("nacionalidade", "id_nacionalidade=?", [1]); 77 | 78 | // Bonus: How to make a master/detail ORM query: 79 | SqlResult master = connection.execute("select client_id, client_name from client"); 80 | SqlResult detail = connection.execute("select client_id, inv_number from invoice"); 81 | master.rows.forEach((r) { 82 | Client client = Client.fromJson(r.toJson()); 83 | client.invoices = detail.rows.where((e) => e.client_id == client.client_id).map((e) => Invoice.fromJson(e.toJson())).toList(); 84 | }); 85 | 86 | print("end of printing."); 87 | connection.close(); 88 | stdin.readLineSync(); 89 | } 90 | -------------------------------------------------------------------------------- /lib/dart_mssql.dart: -------------------------------------------------------------------------------- 1 | library dart_mssql; 2 | 3 | export 'src/sql_connection.dart'; 4 | export 'package:sql_result/sql_result.dart'; 5 | export 'package:sql_recase/sql_recase.dart'; 6 | export 'package:sql_utils/sql_utils.dart'; -------------------------------------------------------------------------------- /lib/src/sql_connection.dart: -------------------------------------------------------------------------------- 1 | import 'dart-ext:dart_mssql'; 2 | import 'package:meta/meta.dart'; 3 | 4 | import 'package:string_utils/string_utils.dart'; 5 | import 'package:sql_result/sql_result.dart'; 6 | import 'package:sql_utils/sql_utils.dart'; 7 | 8 | String _strSlice(String s, [int num = 1]) { 9 | return isEmpty(s) ? "" : s.substring(0, s.length - 1); 10 | } 11 | 12 | class _SqlReturn { 13 | int handle; 14 | String error; 15 | SqlResult result; 16 | } 17 | 18 | _SqlReturn _connectCommand(String host, String databaseName, String username, String passwordword, int authType) native '_connectCommand'; 19 | 20 | _SqlReturn _executeCommand(int handle, String sqlCommand, List params) native '_executeCommand'; 21 | 22 | _SqlReturn _disconnectCommand(int handle) native '_disconnectCommand'; 23 | 24 | /// This is the primary type of this library, a connection is responsible for connecting to databases and executing queries. 25 | class SqlConnection { 26 | 27 | /// Name of database server 28 | String host; 29 | 30 | /// Name of database 31 | String db; 32 | 33 | /// user name used to connect 34 | String user; 35 | 36 | /// password used to connect 37 | String password; 38 | 39 | int _handle = 0; 40 | 41 | SqlConnection({ 42 | @required this.host, @required this.db, this.user, this.password}) { 43 | _SqlReturn r = _connectCommand(host, db, user, password, 0); 44 | if (isNotEmpty(r.error)) { 45 | throw r.error; 46 | } 47 | _handle = r.handle; 48 | } 49 | 50 | void _checkHandle() { 51 | if (_handle <= 0) { 52 | throw "Not connected"; 53 | } 54 | } 55 | 56 | bool _hasSqlError(String error) { 57 | if (isNotEmpty(error)) { 58 | throw error; 59 | } 60 | return false; 61 | } 62 | 63 | _SqlReturn _tryReconnect(_SqlReturn r, String sqlCommand, [List params]) { 64 | if (r.error.indexOf("0x80004005") != -1) { // connection lost. Try reconnecting... 65 | r = _connectCommand(host, db, user, password, 0); 66 | if (!_hasSqlError(r.error)) { 67 | _handle = r.handle; 68 | r = _executeCommand(_handle, sqlCommand, params); // re-execute command 69 | _hasSqlError(r.error); 70 | } 71 | } else { 72 | throw r.error; 73 | } 74 | return r; 75 | } 76 | 77 | 78 | /// Executes a sql command with optional params 79 | SqlResult execute(String sqlCommand, [List params]) { 80 | _checkHandle(); 81 | _SqlReturn r = _executeCommand(_handle, sqlCommand, params); 82 | if (isNotEmpty(r.error)) { 83 | r = _tryReconnect(r, sqlCommand, params); 84 | } 85 | r.result.updateFieldIndexes(); 86 | return r.result; 87 | } 88 | 89 | /// Executes a sql command that returns one single row (allow optional params) 90 | SqlRow selectOne(String sqlCommand, [List params]) { 91 | _checkHandle(); 92 | _SqlReturn r = _executeCommand(_handle, sqlCommand, params); 93 | if (isNotEmpty(r.error)) { 94 | r = _tryReconnect(r, sqlCommand, params); 95 | } 96 | r.result.updateFieldIndexes(); 97 | if (r.result.rows.isEmpty) { 98 | return null; 99 | } else { 100 | return r.result.rows.first; 101 | } 102 | } 103 | 104 | /// Returns the identity column value of last inserted row 105 | int lastIdentity() { 106 | SqlResult r = execute("select @@identity as idty"); 107 | if (r.rows != null && r.rows.isNotEmpty) { 108 | return r.rows.first.idty.round(); 109 | } else { 110 | return null; 111 | } 112 | } 113 | 114 | /// Inserts [row] into [tableName]. 115 | /// Returns the number of rows inserted. 116 | /// if [onlyColumns] is specified, only this columns will be used from [row] map. 117 | /// if [excludedColumns] is specified, all columns from [row] map will be used EXCEPT these ones. 118 | int insert(String tableName, Map row, {List onlyColumns, List excludedColumns}) { 119 | String fieldNames = ""; 120 | String fieldValues = ""; 121 | row.forEach((n, v) { 122 | if ((onlyColumns == null || onlyColumns.contains(n)) && (excludedColumns == null || !excludedColumns.contains(n))) { 123 | fieldNames += n + ','; 124 | if (v is DateTime) { 125 | fieldValues += 126 | "${v == null ? null : "'" + sqlDateTime(v) + "'"},"; 127 | } else if (v is String) { 128 | fieldValues += 129 | "${v == null ? null : "'" + v.replaceAll("'", "''") + "'"},"; 130 | } else { 131 | fieldValues += "$v,"; 132 | } 133 | }; 134 | }); 135 | fieldNames = _strSlice(fieldNames); 136 | fieldValues = _strSlice(fieldValues); 137 | SqlResult r = execute("insert into $tableName($fieldNames) values ($fieldValues)"); 138 | return r.rowsAffected; 139 | } 140 | 141 | /// Updates [row] into [tableName]. 142 | /// Returns the number of rows updated 143 | /// [where] and [whereArgs] will be used as update where clause 144 | /// if [onlyColumns] is specified, only this columns will be used from [row] map 145 | /// if [excludedColumns] is specified, all columns from [row] map will be used EXCEPT these ones 146 | update(String tableName, Map row, String where, List whereArgs, {List onlyColumns, List excludedColumns}) { 147 | assert(isNotEmpty(where) && whereArgs != null && whereArgs.isNotEmpty); 148 | String fieldValues = ""; 149 | row.forEach((n, v) { 150 | if ((onlyColumns == null || onlyColumns.contains(n)) && (excludedColumns == null || !excludedColumns.contains(n))) { 151 | fieldValues += n + '='; 152 | if (v is DateTime) { 153 | fieldValues += 154 | "${v == null ? null : "'" + sqlDateTime(v) + "'"},"; 155 | } else if (v is String) { 156 | fieldValues += 157 | "${v == null ? null : "'" + v.replaceAll("'", "''") + "'"},"; 158 | } else { 159 | fieldValues += "$v,"; 160 | } 161 | } 162 | }); 163 | fieldValues = _strSlice(fieldValues); 164 | SqlResult r = execute("update $tableName set $fieldValues where $where", whereArgs); 165 | return r.rowsAffected; 166 | } 167 | 168 | /// Delete [row] from [tableName]. 169 | /// Returns the number of rows deleted 170 | /// [where] and [whereArgs] will be used as delete where clause 171 | delete(String tableName, String where, List whereArgs) { 172 | assert(isNotEmpty(where) && whereArgs != null && whereArgs.isNotEmpty); 173 | SqlResult r = execute("delete $tableName where $where", whereArgs); 174 | return r.rowsAffected; 175 | } 176 | 177 | /// Closes the connection. Remember to allways close connections afer use 178 | void close() { 179 | if (_handle > 0) { 180 | _disconnectCommand(_handle); 181 | } 182 | _handle = 0; 183 | } 184 | } 185 | 186 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_mssql 2 | description: High Performance Microsoft SQL Server Driver for Dart (32 & 64bits) 3 | version: 1.0.1 4 | author: Moacir Schmidt 5 | homepage: https://www.polygonus.com 6 | repository: https://github.com/MoacirSchmidt/dart_mssql 7 | 8 | environment: 9 | sdk: ">=2.0.0 <3.0.0" 10 | 11 | dependencies: 12 | meta: ^1.1.6 13 | collection: ^1.14.11 14 | string_utils: ^0.2.0 15 | sql_utils: ^0.2.0 16 | sql_recase: ^0.2.1 17 | sql_result: ^0.2.2 --------------------------------------------------------------------------------