| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| /*------------------------------------------------------------------------- |
| * |
| * gppc_client.c |
| * libgppc client program |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #include <stdio.h> |
| #include <string.h> |
| #include "gppc.h" |
| |
| GPPC_FUNCTION_INFO(oidcheckfunc); |
| GppcDatum oidcheckfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum oidcheckfunc(GPPC_FUNCTION_ARGS) |
| { |
| char *arg = GppcTextGetCString(GPPC_GETARG_TEXT(0)); |
| |
| /* |
| * We use INT4 as the result type, because RETURN_OID macros are not prepared. |
| */ |
| if (strcmp("bool", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidBool); |
| else if (strcmp("char", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidChar); |
| else if (strcmp("int2", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidInt2); |
| else if (strcmp("int4", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidInt4); |
| else if (strcmp("int8", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidInt8); |
| else if (strcmp("float4", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidFloat4); |
| else if (strcmp("float8", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidFloat8); |
| else if (strcmp("text", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidText); |
| else if (strcmp("varchar", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidVarChar); |
| else if (strcmp("bpchar", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidBpChar); |
| else if (strcmp("bytea", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidBytea); |
| else if (strcmp("numeric", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidNumeric); |
| else if (strcmp("date", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidDate); |
| else if (strcmp("time", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidTime); |
| else if (strcmp("timetz", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidTimeTz); |
| else if (strcmp("timestamp", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidTimestamp); |
| else if (strcmp("timestamptz", arg) == 0) |
| GPPC_RETURN_INT4(GppcOidTimestampTz); |
| |
| GPPC_RETURN_NULL(); |
| } |
| |
| GPPC_FUNCTION_INFO(boolfunc); |
| GppcDatum boolfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum boolfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcBool arg1 = GPPC_GETARG_BOOL(0); |
| |
| GPPC_RETURN_BOOL(arg1); |
| } |
| |
| GPPC_FUNCTION_INFO(charfunc); |
| GppcDatum charfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum charfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcChar arg1 = GPPC_GETARG_CHAR(0); |
| |
| GPPC_RETURN_CHAR(arg1); |
| } |
| |
| GPPC_FUNCTION_INFO(int2mulfunc); |
| GppcDatum int2mulfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum int2mulfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcInt2 arg1 = GPPC_GETARG_INT2(0); |
| GppcInt2 arg2 = GPPC_GETARG_INT2(1); |
| |
| GPPC_RETURN_INT2(arg1 * arg2); |
| } |
| |
| GPPC_FUNCTION_INFO(int4func1); |
| GppcDatum int4func1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum int4func1(GPPC_FUNCTION_ARGS) |
| { |
| int nargs = GPPC_NARGS(); |
| GppcInt4 arg1; |
| |
| if (nargs < 1) |
| arg1 = 0; |
| else |
| arg1 = GPPC_GETARG_INT4(0); |
| |
| GPPC_RETURN_INT4(arg1); |
| } |
| |
| GPPC_FUNCTION_INFO(int8plusfunc); |
| GppcDatum int8plusfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum int8plusfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcInt8 arg1 = GPPC_GETARG_INT8(0); |
| GppcInt8 arg2 = GPPC_GETARG_INT8(1); |
| |
| GPPC_RETURN_INT8(arg1 + arg2); |
| } |
| |
| GPPC_FUNCTION_INFO(float4func1); |
| GppcDatum float4func1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum float4func1(GPPC_FUNCTION_ARGS) |
| { |
| GppcFloat4 arg1 = GPPC_GETARG_FLOAT4(0); |
| |
| GPPC_RETURN_FLOAT4(arg1 + 1.5); |
| } |
| |
| GPPC_FUNCTION_INFO(float8func1); |
| GppcDatum float8func1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum float8func1(GPPC_FUNCTION_ARGS) |
| { |
| GppcFloat8 arg1 = GPPC_GETARG_FLOAT8(0); |
| |
| GPPC_RETURN_FLOAT8(arg1 / 2.0); |
| } |
| |
| GPPC_FUNCTION_INFO(textdoublefunc); |
| GppcDatum textdoublefunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum textdoublefunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcText arg1 = GPPC_GETARG_TEXT(0); |
| size_t clen = GppcGetTextLength(arg1); |
| GppcText result; |
| |
| result = GppcAllocText(clen * 2); |
| memcpy(GppcGetTextPointer(result), GppcGetTextPointer(arg1), clen); |
| memcpy(GppcGetTextPointer(result) + clen, GppcGetTextPointer(arg1), clen); |
| |
| GPPC_RETURN_TEXT(result); |
| } |
| |
| GPPC_FUNCTION_INFO(textgenfunc); |
| GppcDatum textgenfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum textgenfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcText result = GppcCStringGetText("cstring result"); |
| |
| GPPC_RETURN_TEXT(result); |
| } |
| |
| GPPC_FUNCTION_INFO(textcopyfunc); |
| GppcDatum textcopyfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum textcopyfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcText copy = GPPC_GETARG_TEXT_COPY(0); |
| GppcText arg = GPPC_GETARG_TEXT(0); |
| GppcBool needcopy = GPPC_GETARG_BOOL(1); |
| |
| *(GppcGetTextPointer(copy)) = '!'; |
| |
| GPPC_RETURN_TEXT(needcopy ? copy : arg); |
| } |
| |
| GPPC_FUNCTION_INFO(varchardoublefunc); |
| GppcDatum varchardoublefunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum varchardoublefunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcVarChar arg1 = GPPC_GETARG_VARCHAR(0); |
| size_t clen = GppcGetVarCharLength(arg1); |
| GppcVarChar result; |
| |
| result = GppcAllocVarChar(clen * 2); |
| memcpy(GppcGetVarCharPointer(result), GppcGetVarCharPointer(arg1), clen); |
| memcpy(GppcGetVarCharPointer(result) + clen, GppcGetVarCharPointer(arg1), clen); |
| |
| GPPC_RETURN_VARCHAR(result); |
| } |
| |
| GPPC_FUNCTION_INFO(varchargenfunc); |
| GppcDatum varchargenfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum varchargenfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcVarChar result = GppcCStringGetVarChar("cstring result"); |
| |
| GPPC_RETURN_VARCHAR(result); |
| } |
| |
| GPPC_FUNCTION_INFO(varcharcopyfunc); |
| GppcDatum varcharcopyfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum varcharcopyfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcVarChar copy = GPPC_GETARG_VARCHAR_COPY(0); |
| GppcVarChar arg = GPPC_GETARG_VARCHAR(0); |
| GppcBool needcopy = GPPC_GETARG_BOOL(1); |
| |
| *(GppcGetVarCharPointer(copy)) = '!'; |
| |
| GPPC_RETURN_VARCHAR(needcopy ? copy : arg); |
| } |
| |
| GPPC_FUNCTION_INFO(bpchardoublefunc); |
| GppcDatum bpchardoublefunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum bpchardoublefunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcBpChar arg1 = GPPC_GETARG_BPCHAR(0); |
| size_t clen = GppcGetBpCharLength(arg1); |
| GppcBpChar result; |
| |
| result = GppcAllocBpChar(clen * 2); |
| memcpy(GppcGetBpCharPointer(result), GppcGetBpCharPointer(arg1), clen); |
| memcpy(GppcGetBpCharPointer(result) + clen, GppcGetBpCharPointer(arg1), clen); |
| |
| GPPC_RETURN_BPCHAR(result); |
| } |
| |
| GPPC_FUNCTION_INFO(bpchargenfunc); |
| GppcDatum bpchargenfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum bpchargenfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcBpChar result = GppcCStringGetBpChar("cstring result"); |
| |
| GPPC_RETURN_BPCHAR(result); |
| } |
| |
| GPPC_FUNCTION_INFO(bpcharcopyfunc); |
| GppcDatum bpcharcopyfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum bpcharcopyfunc(GPPC_FUNCTION_ARGS) |
| { |
| GppcBpChar copy = GPPC_GETARG_BPCHAR_COPY(0); |
| GppcBpChar arg = GPPC_GETARG_BPCHAR(0); |
| GppcBool needcopy = GPPC_GETARG_BOOL(1); |
| |
| *(GppcGetBpCharPointer(copy)) = '!'; |
| |
| GPPC_RETURN_BPCHAR(needcopy ? copy : arg); |
| } |
| |
| GPPC_FUNCTION_INFO(errfunc1); |
| GppcDatum errfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum errfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcText arg1 = GPPC_GETARG_TEXT(0); |
| char *cstr; |
| |
| cstr = GppcTextGetCString(arg1); |
| GppcReport(GPPC_NOTICE, "%s", cstr); |
| |
| GPPC_RETURN_NULL(); |
| } |
| |
| GPPC_FUNCTION_INFO(argisnullfunc); |
| GppcDatum argisnullfunc(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum argisnullfunc(GPPC_FUNCTION_ARGS) |
| { |
| if (GPPC_ARGISNULL(0)) |
| GPPC_RETURN_BOOL(true); |
| else |
| GPPC_RETURN_BOOL(false); |
| } |
| |
| GPPC_FUNCTION_INFO(byteafunc1); |
| GppcDatum byteafunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum byteafunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcBytea bytea = GPPC_GETARG_BYTEA_COPY(0); |
| char *mem = GppcGetByteaPointer(bytea); |
| |
| mem[0]++; |
| |
| GPPC_RETURN_BYTEA(bytea); |
| } |
| |
| GPPC_FUNCTION_INFO(numericfunc1); |
| GppcDatum numericfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum numericfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcNumeric numeric = GPPC_GETARG_NUMERIC(0); |
| char *str; |
| |
| str = GppcNumericGetCString(numeric); |
| if (strlen(str) > 0 && ('0' <= str[0] && str[0] <= '8')) |
| str[0]++; |
| |
| GPPC_RETURN_NUMERIC(GppcCStringGetNumeric(str)); |
| } |
| |
| GPPC_FUNCTION_INFO(numericfunc2); |
| GppcDatum numericfunc2(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum numericfunc2(GPPC_FUNCTION_ARGS) |
| { |
| GppcNumeric numeric = GPPC_GETARG_NUMERIC(0); |
| |
| GPPC_RETURN_FLOAT8(GppcNumericGetFloat8(numeric)); |
| } |
| |
| GPPC_FUNCTION_INFO(numericfunc3); |
| GppcDatum numericfunc3(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum numericfunc3(GPPC_FUNCTION_ARGS) |
| { |
| GppcFloat8 flt = GPPC_GETARG_FLOAT8(0); |
| |
| GPPC_RETURN_NUMERIC(GppcFloat8GetNumeric(flt)); |
| } |
| |
| GPPC_FUNCTION_INFO(numericdef1); |
| GppcDatum numericdef1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum numericdef1(GPPC_FUNCTION_ARGS) |
| { |
| GppcInt4 typmod = GPPC_GETARG_INT4(0); |
| int16_t precision, scale; |
| char buf[255]; |
| |
| if (GppcGetNumericDef(typmod, &precision, &scale)) |
| snprintf(buf, 255, "NUMERIC(%d, %d)", precision, scale); |
| else |
| snprintf(buf, 255, "NUMERIC()"); |
| |
| GPPC_RETURN_TEXT(GppcCStringGetText(buf)); |
| } |
| |
| GPPC_FUNCTION_INFO(datefunc1); |
| GppcDatum datefunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum datefunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcDate arg = GPPC_GETARG_DATE(0); |
| GppcTm tm; |
| |
| GppcDateGetTm(arg, &tm); |
| tm.tm_year += 1; |
| tm.tm_mon += 1; |
| tm.tm_mday += 1; |
| |
| GPPC_RETURN_DATE(GppcTmGetDate(&tm)); |
| } |
| |
| GPPC_FUNCTION_INFO(timefunc1); |
| GppcDatum timefunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum timefunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcTime arg = GPPC_GETARG_TIME(0); |
| GppcTm tm; |
| |
| GppcTimeGetTm(arg, &tm); |
| tm.tm_hour += 1; |
| tm.tm_min += 1; |
| tm.tm_sec += 1; |
| |
| GPPC_RETURN_TIME(GppcTmGetTime(&tm)); |
| } |
| |
| GPPC_FUNCTION_INFO(timetzfunc1); |
| GppcDatum timetzfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum timetzfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcTimeTz arg = GPPC_GETARG_TIMETZ(0); |
| GppcTm tm; |
| |
| GppcTimeTzGetTm(arg, &tm); |
| tm.tm_hour += 1; |
| tm.tm_min += 1; |
| tm.tm_sec += 1; |
| |
| GPPC_RETURN_TIMETZ(GppcTmGetTimeTz(&tm)); |
| } |
| |
| GPPC_FUNCTION_INFO(timestampfunc1); |
| GppcDatum timestampfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum timestampfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcTimestamp arg = GPPC_GETARG_TIMESTAMP(0); |
| GppcTm tm; |
| |
| GppcTimestampGetTm(arg, &tm); |
| tm.tm_year += 1; |
| tm.tm_mon += 1; |
| tm.tm_mday += 1; |
| tm.tm_hour += 1; |
| tm.tm_min += 1; |
| tm.tm_sec += 1; |
| |
| GPPC_RETURN_TIMESTAMP(GppcTmGetTimestamp(&tm)); |
| } |
| |
| GPPC_FUNCTION_INFO(timestamptzfunc1); |
| GppcDatum timestamptzfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum timestamptzfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcTimestampTz arg = GPPC_GETARG_TIMESTAMPTZ(0); |
| GppcTm tm; |
| |
| GppcTimestampTzGetTm(arg, &tm); |
| tm.tm_year += 1; |
| tm.tm_mon += 1; |
| tm.tm_mday += 1; |
| tm.tm_hour += 1; |
| tm.tm_min += 1; |
| tm.tm_sec += 1; |
| |
| GPPC_RETURN_TIMESTAMPTZ(GppcTmGetTimestampTz(&tm)); |
| } |
| |
| /* |
| * SPI test 1: run query, get the attribute by number at the final row as string |
| */ |
| GPPC_FUNCTION_INFO(spifunc1); |
| GppcDatum spifunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum spifunc1(GPPC_FUNCTION_ARGS) |
| { |
| char *query = GppcTextGetCString(GPPC_GETARG_TEXT(0)); |
| GppcInt4 attno = GPPC_GETARG_INT4(1); |
| GppcSPIResult result; |
| char *val = NULL; |
| |
| if (GppcSPIConnect() < 0) |
| GppcReport(GPPC_ERROR, "connect error"); |
| |
| result = GppcSPIExec(query, 0); |
| while (result->current < result->processed) |
| { |
| val = GppcSPIGetValue(result, attno, true); |
| result->current++; |
| } |
| |
| GppcSPIFinish(); |
| |
| if (val) |
| GPPC_RETURN_TEXT(GppcCStringGetText(val)); |
| else |
| GPPC_RETURN_NULL(); |
| } |
| |
| /* |
| * SPI test 2: run query, get the attribute by name at the final row as string |
| */ |
| GPPC_FUNCTION_INFO(spifunc2); |
| GppcDatum spifunc2(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum spifunc2(GPPC_FUNCTION_ARGS) |
| { |
| char *query = GppcTextGetCString(GPPC_GETARG_TEXT(0)); |
| char *attname = GppcTextGetCString(GPPC_GETARG_TEXT(1)); |
| GppcSPIResult result; |
| char *val = NULL; |
| |
| if (GppcSPIConnect() < 0) |
| GppcReport(GPPC_ERROR, "connect error"); |
| |
| result = GppcSPIExec(query, 0); |
| while (result->current < result->processed) |
| { |
| val = GppcSPIGetValueByName(result, attname, true); |
| result->current++; |
| } |
| |
| GppcSPIFinish(); |
| |
| if (val) |
| GPPC_RETURN_TEXT(GppcCStringGetText(val)); |
| else |
| GPPC_RETURN_NULL(); |
| } |
| |
| /* |
| * SPI test 3: run query, get the attribute by number at the final row as datum |
| */ |
| GPPC_FUNCTION_INFO(spifunc3); |
| GppcDatum spifunc3(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum spifunc3(GPPC_FUNCTION_ARGS) |
| { |
| char *query = GppcTextGetCString(GPPC_GETARG_TEXT(0)); |
| GppcInt4 attno = GPPC_GETARG_INT4(1); |
| GppcSPIResult result; |
| GppcDatum datum; |
| bool isnull = true; |
| |
| if (GppcSPIConnect() < 0) |
| GppcReport(GPPC_ERROR, "connect error"); |
| |
| result = GppcSPIExec(query, 0); |
| while (result->current < result->processed) |
| { |
| datum = GppcSPIGetDatum(result, attno, &isnull, true); |
| result->current++; |
| } |
| |
| GppcSPIFinish(); |
| |
| if (!isnull) |
| GPPC_RETURN_TEXT(GppcDatumGetText(datum)); |
| else |
| GPPC_RETURN_NULL(); |
| } |
| |
| /* |
| * SPI test 4: run query, get the attribute by name at the final row as datum |
| */ |
| GPPC_FUNCTION_INFO(spifunc4); |
| GppcDatum spifunc4(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum spifunc4(GPPC_FUNCTION_ARGS) |
| { |
| char *query = GppcTextGetCString(GPPC_GETARG_TEXT(0)); |
| char *attname = GppcTextGetCString(GPPC_GETARG_TEXT(1)); |
| GppcSPIResult result; |
| GppcDatum datum; |
| bool isnull = true; |
| |
| if (GppcSPIConnect() < 0) |
| GppcReport(GPPC_ERROR, "connect error"); |
| |
| result = GppcSPIExec(query, 0); |
| while (result->current < result->processed) |
| { |
| datum = GppcSPIGetDatumByName(result, attname, &isnull, true); |
| result->current++; |
| } |
| |
| GppcSPIFinish(); |
| |
| if (!isnull) |
| GPPC_RETURN_TEXT(GppcDatumGetText(datum)); |
| else |
| GPPC_RETURN_NULL(); |
| } |
| |
| /* |
| * The error handler. We can call GppcReport with INFO when ERROR, since it's not |
| * infinite recursion. For test purpose, set 'x' to message when WARNING. |
| */ |
| static void |
| errorcallback(GppcReportInfo info, void *arg) |
| { |
| GppcReportLevel elevel = GppcGetReportLevel(info); |
| |
| if (elevel == GPPC_WARNING && arg) |
| memset(GppcGetTextPointer(arg), 'x', GppcGetTextLength(arg)); |
| else if (elevel == GPPC_ERROR && arg) |
| GppcReport(GPPC_INFO, "inside callback: %s", GppcTextGetCString(arg)); |
| } |
| |
| GPPC_FUNCTION_INFO(errorcallbackfunc1); |
| GppcDatum errorcallbackfunc1(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum |
| errorcallbackfunc1(GPPC_FUNCTION_ARGS) |
| { |
| GppcText arg = GPPC_GETARG_TEXT_COPY(0); |
| char *carg = GppcTextGetCString(arg); |
| GppcReportCallbackState cbinfo; |
| |
| cbinfo = GppcInstallReportCallback(errorcallback, arg); |
| |
| if (strcmp(carg, "info") == 0) |
| GppcReport(GPPC_INFO, "info emit"); |
| else if (strcmp(carg, "warning") == 0) |
| GppcReport(GPPC_WARNING, "warning emit"); |
| else if (strcmp(carg, "error") == 0) |
| GppcReport(GPPC_ERROR, "error emit"); |
| |
| GppcUninstallReportCallback(cbinfo); |
| |
| GPPC_RETURN_TEXT(arg); |
| } |
| |
| #if GP_VERSION_NUM >= 40200 |
| GPPC_FUNCTION_INFO(tablefunc_describe); |
| GppcDatum tablefunc_describe(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum |
| tablefunc_describe(GPPC_FUNCTION_ARGS) |
| { |
| GppcTupleDesc tdesc; |
| GppcInt4 avalue; |
| bool isnull, iserror; |
| GppcTupleDesc odesc; |
| GppcReportCallbackState cbstate; |
| |
| /* For a test purpose to make sure it's working in the describe func */ |
| cbstate = GppcInstallReportCallback(errorcallback, NULL); |
| |
| /* Fetch and validate input */ |
| if (GPPC_NARGS() != 1 || GPPC_ARGISNULL(0)) |
| GppcReport(GPPC_ERROR, "invalid invocation of describe"); |
| |
| /* Now get the tuple descriptor for the ANYTABLE we received */ |
| tdesc = GPPC_TF_INPUT_DESC(0, &iserror); |
| |
| if (iserror) |
| GppcReport(GPPC_ERROR, "cannot build tuple descriptor"); |
| |
| avalue = GPPC_TF_GETARG_INT4(1, &isnull, &iserror); |
| if (iserror) |
| GppcReport(GPPC_ERROR, "function is mal-declared"); |
| if (isnull) |
| GppcReport(GPPC_ERROR, "the second argument should not be NULL"); |
| |
| if (avalue < 1 || avalue > GppcTupleDescNattrs(tdesc)) |
| GppcReport(GPPC_ERROR, "invalid column position %d", avalue); |
| |
| /* Print out the attlen -- just an excuse to use GppcTupleDescAttrLen() */ |
| GppcReport(GPPC_INFO, "attlen is %d", GppcTupleDescAttrLen(tdesc, avalue - 1)); |
| |
| /* Build an output tuple a single column based on the column number above */ |
| odesc = GppcCreateTemplateTupleDesc(1); |
| GppcTupleDescInitEntry(odesc, 1, |
| GppcTupleDescAttrName(tdesc, avalue - 1), |
| GppcTupleDescAttrType(tdesc, avalue - 1), |
| GppcTupleDescAttrTypmod(tdesc, avalue - 1)); |
| |
| GppcUninstallReportCallback(cbstate); |
| |
| /* Finally return that tupdesc */ |
| GPPC_RETURN_TUPLEDESC(odesc); |
| } |
| |
| GPPC_FUNCTION_INFO(tablefunc_project); |
| GppcDatum tablefunc_project(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum |
| tablefunc_project(GPPC_FUNCTION_ARGS) |
| { |
| GppcFuncCallContext fctx; |
| GppcAnyTable scan; |
| GppcTupleDesc out_tupdesc, in_tupdesc; |
| GppcHeapTuple tuple; |
| int position; |
| GppcDatum values[1]; |
| bool nulls[1]; |
| GppcDatum result; |
| |
| /* |
| * Sanity checking, shouldn't occur if our CREATE FUNCTION in SQL is done |
| * correctly. |
| */ |
| if (GPPC_NARGS() != 2 || GPPC_ARGISNULL(0) || GPPC_ARGISNULL(1)) |
| GppcReport(GPPC_ERROR, "invalid invocation of project"); |
| scan = GPPC_GETARG_ANYTABLE(0); |
| position = GPPC_GETARG_INT4(1); |
| |
| /* Basic set-returning function (SRF) protocol, setup the context */ |
| if (GPPC_SRF_IS_FIRSTCALL()) |
| { |
| fctx = GPPC_SRF_FIRSTCALL_INIT(); |
| } |
| fctx = GPPC_SRF_PERCALL_SETUP(); |
| |
| /* Get the next value from the input scan */ |
| out_tupdesc = GPPC_SRF_RESULT_DESC(); |
| in_tupdesc = GppcAnyTableGetTupleDesc(scan); |
| tuple = GppcAnyTableGetNextTuple(scan); |
| |
| /* Based on what the describe callback should have setup */ |
| if (position < 1 || position > GppcTupleDescNattrs(in_tupdesc)) |
| GppcReport(GPPC_ERROR, "invalid column position(%d)", position); |
| if (GppcTupleDescNattrs(out_tupdesc) != 1) |
| GppcReport(GPPC_ERROR, "invalid column length in out_tupdesc"); |
| if (GppcTupleDescAttrType(out_tupdesc, 0) != |
| GppcTupleDescAttrType(in_tupdesc, 0)) |
| GppcReport(GPPC_ERROR, "type mismatch"); |
| |
| /* check for end of scan */ |
| if (tuple == NULL) |
| GPPC_SRF_RETURN_DONE(fctx); |
| |
| /* Construct the output tuple and convert to a datum */ |
| values[0] = GppcGetAttributeByNum(tuple, position, &nulls[0]); |
| result = GppcBuildHeapTupleDatum(out_tupdesc, values, nulls); |
| |
| /* Return the next result */ |
| GPPC_SRF_RETURN_NEXT(fctx, result); |
| } |
| |
| GPPC_FUNCTION_INFO(describe_spi); |
| GppcDatum describe_spi(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum describe_spi(GPPC_FUNCTION_ARGS) |
| { |
| GppcTupleDesc tdesc, odesc; |
| GppcSPIResult result; |
| bool isnull, iserror; |
| char *query; |
| char *colname = NULL; |
| GppcDatum d_colname; |
| |
| tdesc = GPPC_TF_INPUT_DESC(0, &iserror); |
| |
| if (GppcSPIConnect() < 0) |
| GppcReport(GPPC_ERROR, "unable to connect to SPI"); |
| |
| /* Get query string */ |
| query = GppcTextGetCString(GPPC_TF_GETARG_TEXT(1, &isnull, &iserror)); |
| if (isnull || iserror) |
| GppcReport(GPPC_ERROR, "invalid invocation of describe_spi"); |
| |
| result = GppcSPIExec(query, 0); |
| if (result->processed > 0) |
| colname = GppcSPIGetValue(result, 1, true); |
| if (colname == NULL) |
| colname = "?column?"; |
| GppcSPIFinish(); |
| |
| /* Build tuple desc */ |
| odesc = GppcCreateTemplateTupleDesc(1); |
| GppcTupleDescInitEntry(odesc, 1, |
| colname, GppcOidText, -1); |
| |
| d_colname = GppcTextGetDatum(GppcCStringGetText(colname)); |
| /* Pass the query to project */ |
| GPPC_TF_SET_USERDATA(GppcDatumGetByteaCopy(d_colname)); |
| |
| GPPC_RETURN_TUPLEDESC(odesc); |
| } |
| |
| GPPC_FUNCTION_INFO(project_spi); |
| GppcDatum project_spi(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum project_spi(GPPC_FUNCTION_ARGS) |
| { |
| GppcFuncCallContext fctx; |
| GppcAnyTable scan; |
| GppcTupleDesc odesc, idesc; |
| GppcHeapTuple tuple; |
| char colname[255]; |
| GppcDatum values[1]; |
| bool isnull[1]; |
| GppcDatum result; |
| |
| scan = GPPC_GETARG_ANYTABLE(0); |
| /* Get the user context from the describe function */ |
| strcpy(colname, |
| GppcTextGetCString(GppcDatumGetText(GppcByteaGetDatum(GPPC_TF_GET_USERDATA())))); |
| |
| if (GPPC_SRF_IS_FIRSTCALL()) |
| { |
| fctx = GPPC_SRF_FIRSTCALL_INIT(); |
| } |
| fctx = GPPC_SRF_PERCALL_SETUP(); |
| |
| /* Get the next value from the input scan */ |
| odesc = GPPC_SRF_RESULT_DESC(); |
| idesc = GppcAnyTableGetTupleDesc(scan); |
| tuple = GppcAnyTableGetNextTuple(scan); |
| |
| if (tuple == NULL) |
| GPPC_SRF_RETURN_DONE(fctx); |
| |
| values[0] = GppcGetAttributeByNum(tuple, 1, &isnull[0]); |
| if (!isnull[0]) |
| values[0] = GppcTextGetDatum(GppcCStringGetText( |
| strcat(colname, GppcTextGetCString(GppcDatumGetText(values[0]))))); |
| |
| result = GppcBuildHeapTupleDatum(odesc, values, isnull); |
| GPPC_SRF_RETURN_NEXT(fctx, result); |
| } |
| |
| typedef struct MySession |
| { |
| GppcReportCallbackState cbstate; |
| char *message; |
| } MySession; |
| |
| static void |
| tfcallback(GppcReportInfo info, void *arg) |
| { |
| GppcReportLevel elevel = GppcGetReportLevel(info); |
| |
| if (elevel == GPPC_ERROR) |
| { |
| MySession *sess; |
| |
| sess = (MySession *) arg; |
| GppcReport(GPPC_INFO, "message: %s", sess->message); |
| GppcFree(sess); |
| } |
| } |
| |
| GPPC_FUNCTION_INFO(project_errorcallback); |
| GppcDatum project_errorcallback(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum project_errorcallback(GPPC_FUNCTION_ARGS) |
| { |
| GppcFuncCallContext fctx; |
| GppcAnyTable scan; |
| GppcTupleDesc odesc, idesc; |
| GppcHeapTuple tuple; |
| GppcDatum *values; |
| bool *isnull; |
| int i, attnum; |
| GppcDatum result; |
| |
| scan = GPPC_GETARG_ANYTABLE(0); |
| |
| if (GPPC_SRF_IS_FIRSTCALL()) |
| { |
| MySession *sess; |
| |
| fctx = GPPC_SRF_FIRSTCALL_INIT(); |
| sess = (MySession *) GppcSRFAlloc(fctx, sizeof(MySession)); |
| sess->cbstate = GppcInstallReportCallback(tfcallback, sess); |
| sess->message = GppcSRFAlloc(fctx, 255); |
| strcpy(sess->message, "Hello, world!"); |
| |
| /* Save session in the SRF context */ |
| GppcSRFSave(fctx, sess); |
| } |
| fctx = GPPC_SRF_PERCALL_SETUP(); |
| |
| /* |
| * Return the input tuple as is, but it seems |
| * TableFunction doesn't accept tuples with <idesc>, so copy |
| * everything to a new tuple. |
| */ |
| odesc = GPPC_SRF_RESULT_DESC(); |
| idesc = GppcAnyTableGetTupleDesc(scan); |
| tuple = GppcAnyTableGetNextTuple(scan); |
| |
| if (tuple == NULL) |
| { |
| /* End of the input scan */ |
| MySession *sess; |
| |
| sess = (MySession *) GppcSRFRestore(fctx); |
| GppcUninstallReportCallback(sess->cbstate); |
| GppcFree(sess); |
| GPPC_SRF_RETURN_DONE(fctx); |
| } |
| |
| attnum = GppcTupleDescNattrs(idesc); |
| values = GppcAlloc(sizeof(GppcDatum) * attnum); |
| isnull = GppcAlloc(sizeof(bool) * attnum); |
| for (i = 0; i < attnum; i++) |
| { |
| values[i] = GppcGetAttributeByNum(tuple, 1, &isnull[i]); |
| if (i == 0 && isnull[0]) |
| GppcReport(GPPC_ERROR, "first attribute is NULL"); |
| } |
| |
| result = GppcBuildHeapTupleDatum(odesc, values, isnull); |
| GPPC_SRF_RETURN_NEXT(fctx, result); |
| } |
| #endif /* GP_VERSION_NUM >= 40200 */ |
| |
| GPPC_FUNCTION_INFO(test_encoding_name); |
| GppcDatum test_encoding_name(GPPC_FUNCTION_ARGS); |
| |
| GppcDatum |
| test_encoding_name(GPPC_FUNCTION_ARGS) |
| { |
| GppcText res; |
| const char *str = GppcDatabaseEncodingName(GPPC_UTF8); |
| size_t len = strlen(str); |
| |
| res = GppcAllocText(len); |
| memcpy(GppcGetTextPointer(res), str, len); |
| |
| GPPC_RETURN_TEXT(res); |
| } |