database.sarang.net
UserID
Passwd
Database
DBMS
ㆍMySQL
PostgreSQL
Firebird
Oracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
MySQL Devel 23669 게시물 읽기
 News | Q&A | Columns | Tutorials | Devel | Files | Links
No. 23669
MySQL UDF Token() - Tokenizing (Windows version)
작성자
이노성(lnsium)
작성일
2004-03-08 03:01:58
조회수
8,410
첨부파일
파일이름크기Info 
token.zip9.91 KB  

MySQL UDF입니다.
함수명은 TOKEN()입니다.

 

사용법:

[인수의 수가 1인 경우]
token("aaa bbb ccc") --> 'aaa' 리턴
token(" aaa bbb") --> 'NULL'  리턴, 왜냐하면 시작문자가 공백문자로 구분자이기 때문에

 

[인수의 수가 2인 경우]
token("aaa bbb ccc", 2) --> 'bbb' 두번째 토큰을 리턴, 만약 0이면 무시하고 'aaa'를 리턴, 3이면 'ccc', 4이면 'NULL'를 리턴.

token("aa$cc&dd", "$&") --> 'aa'를 리턴, 즉 구분자를 기준으로 첫번째 토큰을 리턴, 만약 "aacc&dd"면 'aacc'를 리턴.

 

[인수의 수가 3인 경우]
token("aa&cc&dd", "&$", 2) --> 'cc'를 리턴
token("aa&cc&dd", 3, "&$") --> 'dd'를 리턴, 즉 두번째 인수와 세번째 인수는 위치가 바꿔도 상관없음.

 

윈도우 환경에서 만들었습니다. 좀만 바꾸면 리눅스등 다른 OS에서도

돌아갈 수 있을겁니다. 조금이라도 도움이 됐으면 좋겠습니다.

저가 여기에 너무 신세진게 많아서리..^^;;

 

//////////////////////////////////////////////////////////////////////////////

// token.h                                                                             //

//////////////////////////////////////////////////////////////////////////////

#include "mysql.h"
#define TOKEN_API extern "C" __declspec(dllexport)

TOKEN_API my_bool token_init( UDF_INIT *initid, UDF_ARGS *args, char *message );
TOKEN_API void token_deinit( UDF_INIT *initid );
TOKEN_API char* token( UDF_INIT *initid, UDF_ARGS *args,
       char *result, unsigned long *length,
       char *is_null, char* /* error */ );


 

//////////////////////////////////////////////////////////////////////////////

// token.cpp                                                                         //

//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "token.h"

 

#define MAX_TOKEN 255
#define DEFAULT_SEPERATORS " \t\n\r"
#define DEFAULT_SEPERATORS_LEN 4
#define DEFAULT_ORDINAL 1

 

struct token_argv
{
 char* seperators;
 int seperators_len;
 int ordinal;  //몇번째 토큰을 가져올까?를 지정
};

 

TOKEN_API my_bool token_init( UDF_INIT *initid, UDF_ARGS *args, char *message )

 enum Item_result *type = args->arg_type;
 int default_seperators = 0;
 int default_ordinal = 0;

 /*구지 여기서 구조체 만들어서 메모리 할당하고 initid를 이용해 넘겨주고
   넘겨받고 할 필요없이 token() 자체에서 할 수 있지만 token()가 갖은 원래
   기능에 집중하기 위해 예비작업을 분리한다. */

 token_argv *argv = new token_argv;
 if( !argv )
 {
  strcpy( message, "Memory alloc failed!" );
  return 1;
 }
 argv->seperators = 0;
 argv->seperators_len = 0;
 argv->ordinal = DEFAULT_ORDINAL;
 
 /*인수의 수와 타입 체크, 초기화*/
 switch( args->arg_count )
 {
 case 1:
  //공백문자를 구분자로 하고 첫번째 토큰을 원하는 경우이다.
  if( type[0] != STRING_RESULT )
  {
   strcpy( message, "Wrong argument type" );
   goto TOKEN_ERROR;
  }  
  break;

 case 2:

  //사용자 지정문자를 구분자로 하고 윈하는 토큰이 첫번째가 아닐 수 있다.
  //두번째 인수가 문자열, 즉 구분자이면 자동으로 첫번째 토큰을 원하는 것으로
  //간주한다. 반대로 두번째 인수가 정수이면 공백문자의 구분자로 지정 토콘을
  //원하는 것으로 간주한다.

  if( type[0] != STRING_RESULT || type[1] == REAL_RESULT )
  {
   strcpy( message, "Wrong argument type" );
   goto TOKEN_ERROR;
  }  

  if( type[1] == INT_RESULT )  
   default_ordinal = 1;
  else if ( args->lengths[1] > 0 )
   default_seperators = 1;  
  break;

 case 3:

  //사용자 지정문자를 구분자로 하고 윈하는 토큰이 첫번째가 아닐 수 있다.
  //구분자와 토큰지정의 위치가 바뀔 수 있다. 이 경우는 매우 제한적인 경우
  //에 필요할 것이다.

  if( type[0] != STRING_RESULT || type[1] == REAL_RESULT
   || type[2] == REAL_RESULT || type[1] == type[2] )
  {
   strcpy( message, "Wrong argument type" );
   goto TOKEN_ERROR;
  } 

  if( type[1] == INT_RESULT )
  {
   default_ordinal = 1;
   if( args->lengths[2] > 0 )
    default_seperators = 2;
  }
  else
  {
   default_ordinal = 2;
   if( args->lengths[1] > 0 )
    default_seperators = 1;
  }
  break;

 default:
  strcpy( message, "Wrong number of arguments" );
  goto TOKEN_ERROR;
 }

 //첫번째 토큰을 원하는게 아니라면
 if( default_ordinal )
 {
  argv->ordinal = *((int*)args->args[default_ordinal]);
  if( argv->ordinal < 1 )
   argv->ordinal = DEFAULT_ORDINAL;
 }

 if( default_seperators ) //공백문자 구분자를 원하는게 아니라면
 {
  argv->seperators = new char[args->lengths[default_seperators]+1];
  if( !argv->seperators )
  {
   strcpy( message, "Memory alloc failed!" );
   goto TOKEN_ERROR;
  }
  strcpy( argv->seperators, args->args[default_seperators] );  
  argv->seperators[args->lengths[default_seperators]] = 0;
  argv->seperators_len = args->lengths[default_seperators];
 }
 else //공백문자 구분자 사용
 {
  argv->seperators = new char[DEFAULT_SEPERATORS_LEN+1];
  if( !argv->seperators )
  {
   strcpy( message, "Memory alloc failed!" );
   goto TOKEN_ERROR;
  }
  strcpy( argv->seperators, DEFAULT_SEPERATORS );
  argv->seperators[DEFAULT_SEPERATORS_LEN] = 0;  
  argv->seperators_len = DEFAULT_SEPERATORS_LEN;
 }

 initid->ptr = (char*)argv;
 initid->max_length = MAX_TOKEN;
 return 0;
 
TOKEN_ERROR:
 if( argv )
 {
  if( argv->seperators )
   delete[] argv->seperators;
  delete argv;
 }
 return 1;
}

 

/*꼭 여기서 메모리를 해제해야할 필요는 없다.
  token()에서 사용하고 해제해도 된다. 그래도 기능분리 원칙에
  따라 여기서 해제한다.*/
TOKEN_API void token_deinit( UDF_INIT *initid )
{
 token_argv *argv = (token_argv*)initid->ptr;
 if( argv )
 {
  if( argv->seperators )
   delete[] argv->seperators;
  delete argv;
 }
}

 

/*리턴값이 255byte 이하라면 별도의 결과값을 위한 메모리 할당 필요없이
  result인수를 사용한다.*/

TOKEN_API char* token( UDF_INIT *initid, UDF_ARGS *args,
       char *result, unsigned long *length,
       char *is_null, char*  /*error */ )
{
 token_argv *argv = (token_argv*)initid->ptr;
 char *str = args->args[0];
 int len = args->lengths[0];

 int index = 0;
 int count = 0;
 int x1 = 0;
 int x2 = len;    

 //핵심 동작 
 while( index <= len )
 {   
  //주위! 종료문자는 자연적 구분자로 본다.
  if( index == len || strchr( argv->seperators, str[index] ) ) //이제 구분자를 찾으면
  {   
   x2 = index;
   count++; //토큰을 찾은 것이므로 count증가
   if( count == argv->ordinal ) //찾던 위치의 토큰이면 중지    
    break;
     
   //다시 연속된 구분자들을 skip한다.
   while( index < len )
   {
    if( !strchr( argv->seperators, str[index] ) )  //구분자가 아니면...     
     break;    
    index++;
   }   
   x1 = index; //토큰의 시작 인덱스를 저장
  }
  index++;
 }

 *is_null = 1;
 if( x2 > x1 )
 { 
  //255byte 제한 때문에  
  *length = ((x2 - x1) <= MAX_TOKEN) ? (x2 - x1) : MAX_TOKEN;
  memcpy( result, str+x1, (size_t)*length );
  *is_null = 0;     
  //마지막 글자의 한글이 짤릴수도 있는데 여기서 그것까지 다루진 않는다.
 }

 return result;
}

이 글에 대한 댓글이 총 1건 있습니다.

드디어 첫작품이 등장하네요.

아마도 많은 이들에게 도움이 될 것으로 생각됩니다.

그리고 개인적인 생각으로 MySQL 의 퍼포먼스를 올리는 가장 좋은 방법은 왠만한 부분은 서버에서 돌리는 방법입니다.

지금 처럼 이런 함수를 만들어서 서버로 할일을 넘기는 거죠.

정재익(advance)님이 2004-03-08 19:01:10에 작성한 댓글입니다.
[Top]
No.
제목
작성자
작성일
조회
23672MySQL UDF - lzo 실시간 자료압축
정재익
2004-02-24
7967
23671MySQL UDF --- il_to_cp1250
정재익
2004-02-24
6692
23670MySQL UDF -- Longest common subsequence
정재익
2004-02-16
7349
23669MySQL UDF Token() - Tokenizing (Windows version) [1]
이노성
2004-03-08
8410
21136MySQL UDF -- Unix user interface
정재익
2004-02-24
9999
21133MySQL UDF -- square()
정재익
2004-02-24
9270
21132MySQL UDF -- soundex
정재익
2004-02-24
8313
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2017 DSN, All rights reserved.
작업시간: 0.067초, 이곳 서비스는
	PostgreSQL v9.6.3으로 자료를 관리합니다