안드로이드 앱 만들어보기

BS가 안드로이드 태블릿을 구매했습니다.
BS는 프로그래머입니다.
당연히 하드웨어가 갖추어졌으므로 간단한 어플을 돌리고 싶어집니다.
그래서 Eclipse 를 설치했습니다.
Eclipse는 안드로이드 SDK 설치 문서에 따라 Eclipse Classic 버전으로 했습니다.

그리고 Android SDK를 설치했습니다.

태블릿의 설정에서 개발자 옵션의 USB 디버깅켜진 상태로 유지를 활성화하고
PC와 연결하여 드라이버를 설치했습니다.
드라이버 설치 관련 포스트

BS가 가지고 있는 태블릿은 4.0.3 버전이라 해당 버전의 SDK만 설치했습니다.
그런데 SDK 도큐먼트가 제외되어 있어서 4.1의 도큐먼트만 다시 설치했습니다.

Eclipse를 실행해서 안드로이드 플러그인을 설치합니다.
아직은 NDK를 사용하지 않을 거라서 NDK는 제외했습니다.

설치가 끝나고 이클립스 재시작 하고 나면
이클립스의 New 다이얼로그에 Android가 추가되어 있습니다.

이제 첫 Hello World를 작성하겠습니다.

우선 Android Application Project를 생성합니다.
위에 있는 New 화면에 보이는 그것!

다음 화면에서 아래와 같이 입력했습니다.
BS는 안드로이드 하드웨어가 4.0.3 뿐이므로 최소 사양을 4.0으로 했습니다.

이제 앱의 아이콘을 설정해야 합니다.
적당한 걸 골라봤습니다.

다음은 Activity를 생성하는 화면입니다.
Activity는 안드로이드 앱에서 유저의 입력을 받는, PC에서 어플리케이션의 윈도 정도를 생각하시면 됩니다.
일단 빈 Activity로 생성했습니다.

USB 디버깅으로 PC와 안드로이드 H/W가 연결되어 있고
위 과정을 모두 따라 하셨으면
이제 실행을 한번 해보겠습니다.
이클립스 메뉴의 Run에 있는 Run을 실행해보세요.
자동으로 앱 APK 파일이 H/W에 설치가 되고 실행이 됩니다.

클라이언트에서 암호화를 지원하지 않습니다??? Encryption not supported on the client

SQL Native Client 라이브러리를 사용해서 작성한 어플리케이션을 실행하는데 이와 같은 메시지가 뜹니다.
SQL Server 설치 미디어로부터 클라이언트 도구 따위를 설치하면 괜찮습니다만…
왜 뜨는지 한참을 찾아보았으나 해결방법이라고는 오로지 레지스트리를 편집하는 것 말고는 없더군요.


Windows Server 2008 R2 Standard 를 설치
-> SQL Server 설치 미디어에서 sqlncli.msi 만 가져와 설치
-> SQL Native Client 라이브러리가 추가됨
-> 어플리케이션 실행
-> 오류


이렇게 되었습니다.
안되어서 설치 미디어로 다시 설치를 해보니

HKLM/SOFTWARE/Microsoft/MSSQLServer/Client/SNI10.0/GeneralFlags/Flag1

이런 레지스트리키가 새로 생기고 해당 키 안에












 Label

 REG_SZ 


 Force protocol encryption 


 Value


 REG_DWORD

 0x00000000 


이런 값이 생겼네요.
그래서 다른 깨끗한 머신에 다시 Native Client만 설치하고 레지스트리에서 위 값을 넣었더니…

실행됩니다.
이건 뭔가요? ㅡ.ㅡ
이제 남은 문제는 어플리케이션 배포판을 어떻게 만들어야 하나… 이군요…

In-Memory Database

In-memory database가 필요했습니다.
그래서 찾아 봤습니다.

Wikipedia 설명

IMDB는 여러가지가 있더군요.
일단 BS가 필요한 IMDB의 조건은…



  • Embedded 가능

  • C++ 지원

  • 공짜!

  • Windows 64비트에서 동작

이렇게 해서 위키에서 소개되는 DB 중 얻은 것은 MySQL, SQLite, BDB 였습니다.

1. MySQL
MySQL은 Server 모듈을 임베디드 하는 방식으로, DB로서의 능력은 이미 검증되어 있죠.
문제는 C API에서 정확히는 MySQL Client 단에서 Windows의 Little Endian UCS2를 사용할 수 없다는 것이죠.

ucs2, utf16, and utf32 cannot be used as a client character set, which means that they do not work for SET NAMES or SET CHARACTER SET.

그래서 일단 제외 되었습니다.

2. SQLite
이것도 이미 검증된 DB이죠. File 기반의 DB이지만 메모리 전용으로도 사용할 수 있습니다.
네… 사용할 수는 있습니다.
하지만 메모리 저장소의 DB에는 오로지 연결을 하나 밖에 만들지 못하고, 트랜잭션 처리 등에서 문제가 있습니다.
물론 메모리만 사용하는 모드에서요…
그래서 제외되었습니다.

3. Berkeley DB
BSD로 알려진 운영체제의 일부로 시작하여 지금은 Oracle BDB로 배포되고 있습니다.
수많은 어플리케이션에서 사용하고 있고 이것도 검증된 DB 이지요.
기본은 SQL 기반이 아닙니다. 약간의 노력과 성능 감소를 들이면 SQL 로도 사용할 수는 있지만요.
이것도 기본적으로 파일에 기반하여 작동하는 DB입니다.
메모리만 사용하도록 하면 저장소를 메모리로 사용하는 것이 아니라 파일로 저장을 하지 않고,
파일 기반에서 캐쉬로 사용하는 공간만을 사용하도록 합니다.
그래서 동적으로 그 크기가 커질 수 없어 BDB로 IMDB를 사용하는 것은 … 쩝… 힘들어보입니다.

이리하여 이런 저런 IMDB를 계속 찾아 보았지만…
BS 입맛에 맞는 라이브러리는 없었습니다.

그래서 BS가 간단하게 만들어 보려고 하고 있네요.
성공하길 기원해 주세용. ㅋ

SQL Server에서 비대칭 키에 권한 할당하기

데이터베이스의 권한 설정과 별도로 설정해야 하네요. 왜지???


GRANT VIEW DEFINITION ON ASYMMETRIC KEY :: some_key TO who
GO
GRANT CONTROL ON ASYMMETRIC KEY :: some_key TO who
GO


이렇게 하면 some_key를 who가 사용할 수 있게 됩니다.

SQL Server의 로그파일을 축소시키기

SQL Server의 로그 파일 크기가 무려 5기가가 넘어버렸습니다.
줄여야지 줄여야지 미루다보니 이렇게 되었네요. ㅎㅎ
어떻게 줄이지? 하다보니 더욱 커져 버렸습니다.
BS는 DBA가 아니라서 잘 몰라요…

찾은 방법

ALTER DATABASE [TestDB] SET RECOVERY SIMPLE WITH NO_WAIT
DBCC SHRINKFILE(TestDB_log, 1, TRUNCATEONLY)
ALTER DATABASE [TestDB] SET RECOVERY FULL WITH NO_WAIT
GO

굳!

SQL Server에 .Net 어셈블리로 기능을 확장해보기

이 글은 Visual Studio 2008 SP1 과 SQL Server 2005 를 기준으로 작성되었습니다.

BS가 이런 저런 이유로 SQL Server에서 순수한 SQL 문법만으로는 처리하기 힘든 몇가지가 있어서
.Net 의 도움을 받으려고 자료를 대충 찾아보고 삽으로 땅을 파서 대충 만든 소스입니다.
약간의 수정??이 필요하지만 기본적인 모습은 갖추고 있습니다. ㅎㅎ


그럼 이제 설명을 시작하겠습니다.

1. SQL Server 프로젝트 만들기
Visual Studio 2008을 실행하여 새 프로젝트에 가면 Visual C#의 데이터베이스 프로젝트 형식에서 찾을 수 있습니다.

사용자 삽입 이미지


 

그리고 DB 정보를 입력합니다.

사용자 삽입 이미지

디버깅에 대한 프롬프트가 하나 뜨는데 디버깅 하는 동안 서버의 모든 관리되는 스레드가 중지됩니다.
즉, .Net 어셈블리를 사용하는 기능이 디버깅동안 중지됨을 말합니다.
일단 No…

프로젝트 생성이 끝났습니다.

2. 코드 추가하기
생성된 프로젝트에 파일을 추가합니다. 타입은 C# 클래스입니다.
이제 생성된 소스에 아래 내용을 넣어봅시다.

using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
using System.Collections;

public partial class MyTest
{
// Table Value Function
[SqlFunction(FillRowMethodName = “FillTVFRow”, TableDefinition = “F1 NVARCHAR(50), F2 INT”)]
public static IEnumerable TestTVF()
{
return new TestTVFReader();
}

// Scalar Value Function
[SqlFunction]
public static SqlString TestSVF()
{
return new SqlString(“Test”);
}

// Stored Procedure
[SqlProcedure]
public static void TestProc()
{
using (SqlConnection conn = new SqlConnection(@”context connection=true”))
{
conn.Open();
SqlTransaction trans = conn.BeginTransaction();
try
{
// Drop Table
{
SqlCommand cmd = new SqlCommand(“IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[TestTable]’) AND type in (N’U’)) DROP TABLE TestTable”, conn, trans);
cmd.ExecuteNonQuery();
}

// Create Table
{
SqlCommand cmd = new SqlCommand(“CREATE TABLE TestTable (F1 NVARCHAR(50) NOT NULL, F2 INT NOT NULL)”, conn, trans);
cmd.ExecuteNonQuery();
}

// Insert Data 1
{
SqlCommand cmd = new SqlCommand(“INSERT INTO TestTable (F1, F2) VALUES (@F1,@F2)”, conn, trans);
cmd.Parameters.Add(“@F1”, SqlDbType.NVarChar, 50);
cmd.Parameters.Add(“@F2”, SqlDbType.Int);
cmd.Parameters[0].Value = “Test Value”;
cmd.Parameters[1].Value = 123;
cmd.ExecuteNonQuery();
cmd.Parameters[0].Value = “Test Value 2”;
cmd.Parameters[1].Value = 456;
cmd.ExecuteNonQuery();
}

// Insert Data 2
{
SqlCommand cmd = new SqlCommand(“INSERT INTO TestTable (F1, F2) SELECT * FROM [TestTVF]()”, conn, trans);
cmd.ExecuteNonQuery();
}

trans.Commit();
}
catch (Exception)
{
trans.Rollback();
}
}
}

public static void FillTVFRow(object row, out SqlString str, out SqlInt32 num)
{
object[] rowarr = (object[])row;
str = (SqlString)(rowarr[0]);
num = (SqlInt32)(rowarr[1]);
}

public class TestTVFReader : IEnumerable
{
public TestTVFReader()
{
}

public IEnumerator GetEnumerator()
{
return new TestTVFEnumerator();
}

private class TestTVFEnumerator : IEnumerator
{
int pos;

public TestTVFEnumerator()
{
Reset();
}

public void Reset()
{
pos = -1;
}

public bool MoveNext()
{
++pos;
return (pos < 2);
}

public object Current
{
get
{
object[] row = new Object[2];
row[0] = new SqlString(“Test”);
row[1] = new SqlInt32(10);
return row;
}
}
}
}
}



3. 이제 배포를 해 봅니다.
빌드 메뉴에서 솔루션 배포를 선택합니다.
배포하고 나면 아래와 같이 확인이 됩니다.

사용자 삽입 이미지


4. 테스트 해보기
SQL Server Management Studio 를 통해서 쿼리를 실행해 봅니다.
SELECT * FROM [dbo].[TestTVF]();
SELECT [dbo].[TestSVF]();
EXEC [dbo].[TestProc];
SELECT * FROM [TestTable];

5. 예제 소스 파일

cfile10.uf.13445E3B5006322605741C.cs


SQL Server 2005 비-XML 서식 파일

MSDN 문서 링크

위 문서를 보시면 아주 자세하게 설명되어 있습니다. (비 XML 서식 파일 이해로 검색 하시면 버전별로 나오네요.)
간단한 예제 파일로 BS가 디버깅용으로 쓰는 로그 테이블을 위한 서식 파일입니다.
(BS는 XML 몰라요~ 이런 게 더 편해요)

9.0
7
1 SQLDATETIME 0 8 "" 1 log_date ""
2 SQLNCHAR 2 512 "" 2 log_msg_1 ""
3 SQLNCHAR 2 512 "" 3 log_msg_2 ""
4 SQLNCHAR 2 512 "" 4 log_msg_3 ""
5 SQLNCHAR 2 512 "" 5 log_msg_4 ""
6 SQLNCHAR 2 512 "" 6 log_msg_5 ""
7 SQLNCHAR 2 512 "" 7 log_msg_6 ""

이것이 저장되는 테이블의 모습입니다.

CREATE TABLE [log]
(
	[log_date] [datetime] NOT NULL,
	[log_msg_1] [nvarchar](256) NOT NULL,
	[log_msg_2] [nvarchar](256) NOT NULL,
	[log_msg_3] [nvarchar](256) NOT NULL,
	[log_msg_4] [nvarchar](256) NOT NULL,
	[log_msg_5] [nvarchar](256) NOT NULL,
	[log_msg_6] [nvarchar](256) NOT NULL
)

bcp 등에서 사용됩니다.

ODBC Connection String으로 연결하기

ODBC를 사용하는 프로그램 작성할 때에… 런차임 환경에 ODBC 관리자를 통해 매번 DSN 등록하여 사용하는 것이 불편할 경우 아래와 같은 방법으로 FileDSN을 만들어 사용할 수 있습니다.

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <odbcinst.h>
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	SQLCreateDataSource(GetDesktopWindow(), NULL);
	return 0;
}

완성된 실행 파일을 올립니다.

cfile25.uf.183B7C46500631F43877F1.7z

이것으로 일단 File DSN을 만들 수 있습니다.

그럼 사용할 때에는 어떻게 하는가?

.Net Framework에서는
System::Data::Odbc::OdbcConnection(“FILEDSN=<파일전체경로>;UID=<DBMS 계정>;PWD=<DBMS 암호>;”);
이런 식으로 하시면 되구요.
C에서는
SQLDriverConnect() 함수를 사용하시면 됩니다.

주의할 사항은 FILEDSN 지정할 때에 반드시 전체 경로를 입력해야 한다는 것입니다!!!
C 함수 fullpath() 등을 이용하시면 쉽게 상대 경로로부터 전체 경로를 구할 수 있습니다.

이것을 응용해서 다음과 같은 Connection String으로 DSN 없이 바로 사용할 수도 있습니다.

System::Data::Odbc::OdbcConnection(“DRIVER=SQL Native Client;SERVER=127.0.0.1;UID=<DBMS 계정>;PWD=<DBMS 암호>;”);
위의 내용들은 GenFileDSN으로 파일 저장하면 나오는 내용을 세미콜론으로 이어 붙인 것입니다.