static dsc* execute_concatenate( qli_nod* node, const dsc* value1, const dsc* value2) { /************************************** * * e x e c u t e _ c o n c a t e n a t e * ************************************** * * Functional description * Concatenate two strings. * **************************************/ Firebird::VaryStr<32> temp1; const TEXT* address1; USHORT length1 = MOVQ_get_string(value1, &address1, &temp1, sizeof(temp1)); Firebird::VaryStr<32> temp2; const TEXT* address2; USHORT length2 = MOVQ_get_string(value2, &address2, &temp2, sizeof(temp2)); dsc* desc = &node->nod_desc; vary* avary = (vary*) desc->dsc_address; TEXT* p = avary->vary_string; length1 = MIN(length1, desc->dsc_length - 2); length2 = MAX(MIN(length2, desc->dsc_length - 2 - length1), 0); fb_assert(static_cast<ULONG>(length1) + length2 <= MAX_USHORT - 2); if (length1) { memcpy(p, address1, length1); p += length1; } if (length2) memcpy(p, address2, length2); avary->vary_length = length1 + length2; return desc; }
static bool sleuth( qli_nod* node, const dsc* desc1, const dsc* desc2, const dsc* desc3) { /************************************** * * s l e u t h * ************************************** * * Functional description * Return true if a string (p1, l1) matches a given pattern (p2, l2), * using a pattern language defined in p3, l3. * **************************************/ // Get operator definition string (control string) Firebird::VaryStr<TEMP_STR_LENGTH> temp1; const TEXT* p1; SSHORT l1 = MOVQ_get_string(desc3, &p1, &temp1, TEMP_STR_LENGTH); // Get address and length of search string Firebird::VaryStr<TEMP_STR_LENGTH> temp2; const TEXT* p2; SSHORT l2 = MOVQ_get_string(desc2, &p2, &temp2, TEMP_STR_LENGTH); // Merge search and control strings UCHAR control[256]; l2 = sleuth_merge((const UCHAR*) p2, (const UCHAR*) p1, (const UCHAR*) (p1 + l1), control); // If source is not a blob, do a simple search if (desc1->dsc_dtype != dtype_blob) { l1 = MOVQ_get_string(desc1, &p1, &temp1, TEMP_STR_LENGTH); return sleuth_check(0, (const UCHAR*) p1, (const UCHAR*) (p1 + l1), control, control + l2); } // Source string is a blob, things get interesting bool result = false; FB_API_HANDLE blob = EXEC_open_blob(node->nod_arg[0]); TEXT fixed_buffer[512]; USHORT buffer_length = sizeof(fixed_buffer); TEXT* buffer = make_blob_buffer( blob, &buffer_length); if (!buffer) buffer = fixed_buffer; ISC_STATUS_ARRAY status_vector; while (!isc_get_segment(status_vector, &blob, (USHORT*) &l1, buffer_length, buffer)) if (sleuth_check(0, (UCHAR*) buffer, (UCHAR*) (buffer + l1), control, control + l2)) { result = true; break; } if (buffer != fixed_buffer) gds__free(buffer); if (isc_close_blob(status_vector, &blob)) { qli_ctx* context = (qli_ctx*) node->nod_arg[e_fld_context]; qli_req* request = context->ctx_request; qli_dbb* dbb = request->req_database; ERRQ_database_error(dbb, status_vector); } return result; }
static bool string_boolean( qli_nod* node) { /************************************** * * s t r i n g _ b o o l e a n * ************************************** * * Functional description * Perform one of the complex string functions CONTAINING, MATCHES, * or STARTS WITH. * **************************************/ const DSC *desc1, *desc2, *desc3; if (!(desc1 = EVAL_value(node->nod_arg[0])) || (desc1->dsc_missing & DSC_missing) || !(desc2 = EVAL_value(node->nod_arg[1])) || (desc2->dsc_missing & DSC_missing) || (node->nod_arg[2] && (!(desc3 = EVAL_value(node->nod_arg[2])) || (desc3->dsc_missing & DSC_missing)))) { return false; } if (node->nod_type == nod_sleuth) return sleuth(node, desc1, desc2, desc3); // Get address and length of strings const TEXT* p2; Firebird::VaryStr<TEMP_STR_LENGTH> temp2; SSHORT l2 = MOVQ_get_string(desc2, &p2, &temp2, TEMP_STR_LENGTH); // If source is not a blob, do a simple search if (desc1->dsc_dtype != dtype_blob) { Firebird::VaryStr<TEMP_STR_LENGTH> temp1; const TEXT* p1; SSHORT l1 = MOVQ_get_string(desc1, &p1, &temp1, TEMP_STR_LENGTH); return string_function(node, l1, p1, l2, p2); } // Source string is a blob, things get interesting bool result = false; FB_API_HANDLE blob = EXEC_open_blob(node->nod_arg[0]); TEXT fixed_buffer[512]; USHORT buffer_length = sizeof(fixed_buffer); TEXT* buffer = make_blob_buffer( blob, &buffer_length); if (!buffer) buffer = fixed_buffer; ISC_STATUS_ARRAY status_vector; SSHORT l3 = 0; while (!isc_get_segment(status_vector, &blob, (USHORT*) &l3, buffer_length, buffer)) { if (string_function(node, l3, buffer, l2, p2)) { result = true; break; } } if (buffer != fixed_buffer) gds__free(buffer); if (isc_close_blob(status_vector, &blob)) { qli_ctx* context = (qli_ctx*) node->nod_arg[e_fld_context]; qli_req* request = context->ctx_request; qli_dbb* database = request->req_database; ERRQ_database_error(database, status_vector); } return result; }
static bool string_function(qli_nod* node, SSHORT l1, const TEXT* p1, SSHORT l2, const TEXT* p2) { /************************************** * * s t r i n g _ f u n c t i o n * ************************************** * * Functional description * Perform one of the complex string functions CONTAINING, MATCHES, * or STARTS WITH. * **************************************/ // Handle "STARTS WITH" if (node->nod_type == nod_starts) { if (l1 < l2) return false; if (l2) return memcmp(p1, p2, l2) == 0; return true; } // Handle CONTAINS if (node->nod_type == nod_containing) { while (l1 >= l2) { --l1; const TEXT* q1 = p1++; const TEXT* q2 = p2; SSHORT l = l2; TEXT c1, c2; do { if (--l < 0) return true; c1 = *q1++; c2 = *q2++; } while (UPPER(c1) == UPPER(c2)); } return false; } // Handle LIKE if (node->nod_type == nod_like) { TEXT c1 = 0; Firebird::VaryStr<16> temp; const TEXT* q1 = NULL; if (node->nod_count > 2 && MOVQ_get_string(EVAL_value(node->nod_arg[2]), &q1, &temp, sizeof(temp))) { c1 = *q1; } if (like((const UCHAR*) p1, l1, (const UCHAR*) p2, l2, c1)) return true; return false; } // Handle MATCHES return node->nod_type == nod_matches && matches(p1, l1, p2, l2); }
static void edit_alpha(const dsc* desc, pics* picture, TEXT** output, USHORT max_length) { /************************************** * * e d i t _ a l p h a * ************************************** * * Functional description * Edit data from a descriptor through an edit string to a running * output pointer. * **************************************/ Firebird::VaryStr<512> temp; const TEXT* p = NULL; const USHORT l = MOVQ_get_string(desc, &p, &temp, sizeof(temp)); const TEXT* const end = p + l; picture->pic_pointer = picture->pic_string; picture->pic_count = 0; TEXT* out = *output; while (p < end) { if ((out - *output) >= max_length) break; TEXT c = generate(picture); if (!c || c == '?') break; c = UPPER(c); switch (c) { case 'X': *out++ = *p++; break; case 'A': if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) *out++ = *p++; else IBERROR(69); // Msg 69 conversion error break; case 'B': *out++ = ' '; break; case '"': case '\'': case '\\': literal(picture, c, &out); break; default: *out++ = c; break; } } *output = out; }