473,396 Members | 2,129 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Java UDF Questions re scratchpads

I've been playing with Java UDFs for the last couple of days and I've got
some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.

Somewhere in the manuals, I found some remarks that said I could either
manage my scratchpad with the getScratchpad() and setScratchpad() methods
*OR* set up my own class variables to keep the state between invocations of
the UDF. (I can't find those remarks again right now but I know I saw them.)
I proved that those remarks were correct by developing two successful
variants of the same simple UDF. The code is appended below.

My question is, having tried writing both, why would anyone use
getScratchpad() and setScratchpad() when it is so much easier to just write
each value that needs to be saved to a class variable? The latter approach
is easier and much more concise since you don't have to set up and read the
byte streams that are required to work with getScratchpad() and
setScratchpad().

Still, I know that the developers at IBM are not fools so I assume there are
some genuine benefits to use getScratchpad() and setScratchpad() or some
major risks or limitations to just using class variables so I would be very
interested in hearing more about those risks and benefits. That would help
me choose the best coding style for UDFs.

Here is the code I wrote contrasting the two approaches to scratchpads so
that everyone can see the differences in the size of the two methods. This
code was written using the DB2GENERAL parameter style since the JAVA
parameter style doesn't support scratchpads.

----------------------------------------------------------------------------
---------------------
public class CountRows extends UDF {

/**
* The scratchpad for the numberLines() method. It *must* be initialized
outside of
* the method.
*/
private int lineCounter = 0;

/**
* The row counter for the numberRows() method. It *must* be initialized
outside of
* the method.
*/
private int rowCounter = 0;

/** The scratchpad buffer for the numberRows() method. */
private byte[] scratchpadBuffer;
/**
* Method numberLines() is used to number the lines of a result set.
*
* <p>This method accomplishes the same result as the numberRows()
method elsewhere
* in this class but uses a class variable instead of the
'getScratchpad()' and
* 'setScratchpad()' methods so that developers can make an informed
comparison
* between the two approaches.</p>
*
* @return int the current number of lines in the result set
* @throws Exception
*/
public void numberLines(int lineCount) throws Exception {

String METHOD_NAME = "numberLines()";

try {

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of
the result set will be
* numbered 1, 2, 3, etc.
*/
lineCounter++;

/* Return the value of the line counter. */
set(1, lineCounter);
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("countRows() - " +
excp.getMessage());
}
}
/**
* Method numberRows() is used to number the rows of a result set.
*
* <p>This method accomplishes the same result as the numberLines()
method elsewhere
* in this class but uses the 'getScratchpad()' and 'setScratchpad()'
methods
* instead of a class variable so that developers can make an informed
comparison
* between the two approaches.</p>
*
* @return int the current number of rows in the result set
* @throws Exception
*/
public void numberRows(int lineCount) throws Exception {

String METHOD_NAME = "numberRows()";

try {
/* Initialize the scratchpad buffer. */
scratchpadBuffer = getScratchpad();

/* Read the contents of the DB2 scratchpad. */
ByteArrayInputStream byteArrayInputStream = new
ByteArrayInputStream(scratchpadBuffer);
DataInputStream dataInputStream = new
DataInputStream(byteArrayInputStream);

/* Write a byte stream containing the initial value of the row
counter, which is 0. */
ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
DataOutputStream dataOutputStream = new
DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt(rowCounter);

/*
* Copy the byte stream to a byte array. Copy that byte array to
*another* byte array.
* Set the DB2 scratchpad equal to the second byte array.
*/
byte[] byteArrayBuffer = byteArrayOutputStream.toByteArray();
for(int ix = 0; ix < byteArrayBuffer.length; ix++) {
scratchpadBuffer[ix] = byteArrayBuffer[ix];
}
setScratchpad(scratchpadBuffer);

/* Get the DB2 scratchpad and parse it to get the current value
of the row counter. */
byte[] scratchpadBuffer = getScratchpad();
rowCounter = dataInputStream.readInt();

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of
the result set will
* be numbered 1, 2, 3, etc.
*/
rowCounter++;

/* Return the value of the row counter. */
set(1, rowCounter);
} catch (IOException excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
}
}
}
----------------------------------------------------------------------------
---------------------
--
Rhino
Nov 12 '05 #1
4 1803
Rhino wrote:
I've been playing with Java UDFs for the last couple of days and I've got
some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.

Somewhere in the manuals, I found some remarks that said I could either
manage my scratchpad with the getScratchpad() and setScratchpad() methods
*OR* set up my own class variables to keep the state between invocations of
the UDF. (I can't find those remarks again right now but I know I saw them.)
I proved that those remarks were correct by developing two successful
variants of the same simple UDF. The code is appended below.

My question is, having tried writing both, why would anyone use
getScratchpad() and setScratchpad() when it is so much easier to just write
each value that needs to be saved to a class variable? The latter approach
is easier and much more concise since you don't have to set up and read the
byte streams that are required to work with getScratchpad() and
setScratchpad().

Still, I know that the developers at IBM are not fools so I assume there are
some genuine benefits to use getScratchpad() and setScratchpad() or some
major risks or limitations to just using class variables so I would be very
interested in hearing more about those risks and benefits. That would help
me choose the best coding style for UDFs.


I wrote a (table) UDF that connected to a remote thingy, performed an
operation, and would get back a set of results. I would retrieve all
the results, stick them on my scratchpad, and disconnect in the init
phase. In the row-returning phase (I don't have the code or a manual
nearby, unfortunately) I would simply pull a row off the scratchpad and
return it.

I do not know how easy this would be with a class variable, I come from
a C background and the scratchpad made a lot of sense at the time.

--
Rob Wilson
Nov 12 '05 #2
I really can't think of any REAL reason why you'd use the scratchpad
method instead of a class variable.

The scratchpad is a holdover from C UDFs, where there was no nice object
structure to work with; there were just functions on a library, so DB2
needed a mechansim for UDFs to pass information from one invocation to
the next within the same query. This style of information passing was
simply preserved for parameter style DB2GENERAL -- probably so that
developers used to coding procedure-style C routines could somewhat
comfortably adjust to coding in object-oriented JAVA without having to
learn new concepts.

However, DB2GENERAL will actually create an object instance behind the
scenes for each instance of the UDF in a given query and invoke that
specified member function of that object. Therefore, you can due to the
object oriented nature of that parameter style just create a member
variable of the class, and initialize it in the constructor of your UDF
class and set that instead it will work just fine.

However, using the scratchpad absolutely GAURANTEES that within the same
query, the information in the scratchpad will travel from one invocation
of the method to the next as is, without being altered from what it was
set to. If instead you store your data as a member object inside your
class, DB2 does not "know" about that member variable and cannot
directly maintain it -- that's controlled by JAVA and the fact that DB2
uses the same object from UDF invocation to invocation within the same
query.

In THEORY, however, DB2 might decide that it needs to discard it's
current object and build an new one to continue the query. I this case,
DB2 could easily still preserve the scratchpad for this new object,
but any information in the old object -- of which DB2 has no information
-- would be lost.

That being said, though, any instances where DB2 could POTENTIALLY want
to use a new object instance -- and there are none now that I know of --
should be severe enough to warrant failing the entire statement anyway.

Of course, I obviously cannot predict all the possibilities there either.

NOTE: you CAN NOT use static members of a class to pass information
between different UDF methods inside the same class, or to the NEXT
query that contains the UDF. There is absolutely no gaurentee at all
that that information will persist, or even that different invocations
of the UDF will be inside the same process. I just figured it was
extremely important to mention this.

I hope that helps.

amurchis

**
Disclaimer:
The opinions expressed above are my own and do not necessarily reflect
the business opinion of IBM
**

Rhino wrote:
I've been playing with Java UDFs for the last couple of days and I've got
some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.

Somewhere in the manuals, I found some remarks that said I could either
manage my scratchpad with the getScratchpad() and setScratchpad() methods
*OR* set up my own class variables to keep the state between invocations of
the UDF. (I can't find those remarks again right now but I know I saw them.)
I proved that those remarks were correct by developing two successful
variants of the same simple UDF. The code is appended below.

My question is, having tried writing both, why would anyone use
getScratchpad() and setScratchpad() when it is so much easier to just write
each value that needs to be saved to a class variable? The latter approach
is easier and much more concise since you don't have to set up and read the
byte streams that are required to work with getScratchpad() and
setScratchpad().

Still, I know that the developers at IBM are not fools so I assume there are
some genuine benefits to use getScratchpad() and setScratchpad() or some
major risks or limitations to just using class variables so I would be very
interested in hearing more about those risks and benefits. That would help
me choose the best coding style for UDFs.

Here is the code I wrote contrasting the two approaches to scratchpads so
that everyone can see the differences in the size of the two methods. This
code was written using the DB2GENERAL parameter style since the JAVA
parameter style doesn't support scratchpads.

----------------------------------------------------------------------------
---------------------
public class CountRows extends UDF {

/**
* The scratchpad for the numberLines() method. It *must* be initialized
outside of
* the method.
*/
private int lineCounter = 0;

/**
* The row counter for the numberRows() method. It *must* be initialized
outside of
* the method.
*/
private int rowCounter = 0;

/** The scratchpad buffer for the numberRows() method. */
private byte[] scratchpadBuffer;
/**
* Method numberLines() is used to number the lines of a result set.
*
* <p>This method accomplishes the same result as the numberRows()
method elsewhere
* in this class but uses a class variable instead of the
'getScratchpad()' and
* 'setScratchpad()' methods so that developers can make an informed
comparison
* between the two approaches.</p>
*
* @return int the current number of lines in the result set
* @throws Exception
*/
public void numberLines(int lineCount) throws Exception {

String METHOD_NAME = "numberLines()";

try {

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of
the result set will be
* numbered 1, 2, 3, etc.
*/
lineCounter++;

/* Return the value of the line counter. */
set(1, lineCounter);
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("countRows() - " +
excp.getMessage());
}
}
/**
* Method numberRows() is used to number the rows of a result set.
*
* <p>This method accomplishes the same result as the numberLines()
method elsewhere
* in this class but uses the 'getScratchpad()' and 'setScratchpad()'
methods
* instead of a class variable so that developers can make an informed
comparison
* between the two approaches.</p>
*
* @return int the current number of rows in the result set
* @throws Exception
*/
public void numberRows(int lineCount) throws Exception {

String METHOD_NAME = "numberRows()";

try {
/* Initialize the scratchpad buffer. */
scratchpadBuffer = getScratchpad();

/* Read the contents of the DB2 scratchpad. */
ByteArrayInputStream byteArrayInputStream = new
ByteArrayInputStream(scratchpadBuffer);
DataInputStream dataInputStream = new
DataInputStream(byteArrayInputStream);

/* Write a byte stream containing the initial value of the row
counter, which is 0. */
ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
DataOutputStream dataOutputStream = new
DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt(rowCounter);

/*
* Copy the byte stream to a byte array. Copy that byte array to
*another* byte array.
* Set the DB2 scratchpad equal to the second byte array.
*/
byte[] byteArrayBuffer = byteArrayOutputStream.toByteArray();
for(int ix = 0; ix < byteArrayBuffer.length; ix++) {
scratchpadBuffer[ix] = byteArrayBuffer[ix];
}
setScratchpad(scratchpadBuffer);

/* Get the DB2 scratchpad and parse it to get the current value
of the row counter. */
byte[] scratchpadBuffer = getScratchpad();
rowCounter = dataInputStream.readInt();

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of
the result set will
* be numbered 1, 2, 3, etc.
*/
rowCounter++;

/* Return the value of the row counter. */
set(1, rowCounter);
} catch (IOException excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
}
}
}
----------------------------------------------------------------------------
---------------------

Nov 12 '05 #3
To do this using a member variable (rough coding, just so you get the
idea) --

class MyUDF extends UDF
{
ResultSetClass externalRes = null;
// External connection object if necessary

public void MyTableFunction(...)
{
switch(getCallType())
{
case SQLUDF_TF_OPEN:
{
// Open your remote connection
externalRes = // whatever command you use
// Close connection -- maybe keep it around
// as another member if that would close your
// result set
break;
}
case SQLUDF_TF_FETCH:
{
// If there are still results
if(externalRes.Read())
{
// Set the results values into the return values of the UDF
}
else
{
setSQLstate("02000");
}
break;
}
case SQLUDF_TF_CLOSE:
{
if (externalRes != null)
{
externalRes.close();
externalRes = null;
}
// Similar for external connection if necessary
break;
}
default:
// nothing -- we're not using FIRST or FINAL call
break;
}
}
}

Of course, you may not WANT to have that external resource connection
open all the time while you're processing the data if you need it open
to maintain your result object. However, even if that WAS the case, you
could still read your result data into some kind of local member
object anyway instead of into the scratchpad.
Rob Wilson wrote:

I wrote a (table) UDF that connected to a remote thingy, performed an
operation, and would get back a set of results. I would retrieve all
the results, stick them on my scratchpad, and disconnect in the init
phase. In the row-returning phase (I don't have the code or a manual
nearby, unfortunately) I would simply pull a row off the scratchpad and
return it.

I do not know how easy this would be with a class variable, I come from
a C background and the scratchpad made a lot of sense at the time.

Nov 12 '05 #4
Thanks for your reply to my question!

I was just wondering if there was a big "gotcha" waiting for me if I relied
on class variables instead of getScratchpad()/setScratchpad(). It sounds
like I *should* be safe using class variables but not as if you are actually
certain that there will never be a case where I will regret it ;-)

I see from your email address that you are an IBMer. I hope this isn't nosy
or rude or anything but do you work on the DB2 team at the Toronto lab in
some capacity or are you in some other department? I'm just curious whether
you have "inside" knowledge or if you are just a "regular user" like me? I'm
not going to hold you to anything you say or sue IBM if it turns out to be
incorrect; I'm just trying to understand how much you actually know about
the internals of DB2 and its Java support and how much you're just inferring
from the manuals and your own experience.

Rhino

"amurchis" <am******@ca.ibm.com> wrote in message
news:42********@news3.prserv.net...
I really can't think of any REAL reason why you'd use the scratchpad
method instead of a class variable.

The scratchpad is a holdover from C UDFs, where there was no nice object
structure to work with; there were just functions on a library, so DB2
needed a mechansim for UDFs to pass information from one invocation to
the next within the same query. This style of information passing was
simply preserved for parameter style DB2GENERAL -- probably so that
developers used to coding procedure-style C routines could somewhat
comfortably adjust to coding in object-oriented JAVA without having to
learn new concepts.

However, DB2GENERAL will actually create an object instance behind the
scenes for each instance of the UDF in a given query and invoke that
specified member function of that object. Therefore, you can due to the
object oriented nature of that parameter style just create a member
variable of the class, and initialize it in the constructor of your UDF
class and set that instead it will work just fine.

However, using the scratchpad absolutely GAURANTEES that within the same
query, the information in the scratchpad will travel from one invocation
of the method to the next as is, without being altered from what it was
set to. If instead you store your data as a member object inside your
class, DB2 does not "know" about that member variable and cannot
directly maintain it -- that's controlled by JAVA and the fact that DB2
uses the same object from UDF invocation to invocation within the same
query.

In THEORY, however, DB2 might decide that it needs to discard it's
current object and build an new one to continue the query. I this case,
DB2 could easily still preserve the scratchpad for this new object,
but any information in the old object -- of which DB2 has no information
-- would be lost.

That being said, though, any instances where DB2 could POTENTIALLY want
to use a new object instance -- and there are none now that I know of --
should be severe enough to warrant failing the entire statement anyway.

Of course, I obviously cannot predict all the possibilities there either.

NOTE: you CAN NOT use static members of a class to pass information
between different UDF methods inside the same class, or to the NEXT
query that contains the UDF. There is absolutely no gaurentee at all
that that information will persist, or even that different invocations
of the UDF will be inside the same process. I just figured it was
extremely important to mention this.

I hope that helps.

amurchis

**
Disclaimer:
The opinions expressed above are my own and do not necessarily reflect
the business opinion of IBM
**

Rhino wrote:
I've been playing with Java UDFs for the last couple of days and I've got some questions about scratchpads. I'm running DB2 LUW V8 (FP8) on WinXP.

Somewhere in the manuals, I found some remarks that said I could either
manage my scratchpad with the getScratchpad() and setScratchpad() methods *OR* set up my own class variables to keep the state between invocations of the UDF. (I can't find those remarks again right now but I know I saw them.) I proved that those remarks were correct by developing two successful
variants of the same simple UDF. The code is appended below.

My question is, having tried writing both, why would anyone use
getScratchpad() and setScratchpad() when it is so much easier to just write each value that needs to be saved to a class variable? The latter approach is easier and much more concise since you don't have to set up and read the byte streams that are required to work with getScratchpad() and
setScratchpad().

Still, I know that the developers at IBM are not fools so I assume there are some genuine benefits to use getScratchpad() and setScratchpad() or some
major risks or limitations to just using class variables so I would be very interested in hearing more about those risks and benefits. That would help me choose the best coding style for UDFs.

Here is the code I wrote contrasting the two approaches to scratchpads so that everyone can see the differences in the size of the two methods. This code was written using the DB2GENERAL parameter style since the JAVA
parameter style doesn't support scratchpads.


--------------------------------------------------------------------------

--
---------------------
public class CountRows extends UDF {

/**
* The scratchpad for the numberLines() method. It *must* be initialized outside of
* the method.
*/
private int lineCounter = 0;

/**
* The row counter for the numberRows() method. It *must* be initialized outside of
* the method.
*/
private int rowCounter = 0;

/** The scratchpad buffer for the numberRows() method. */
private byte[] scratchpadBuffer;
/**
* Method numberLines() is used to number the lines of a result set.
*
* <p>This method accomplishes the same result as the numberRows()
method elsewhere
* in this class but uses a class variable instead of the
'getScratchpad()' and
* 'setScratchpad()' methods so that developers can make an informed
comparison
* between the two approaches.</p>
*
* @return int the current number of lines in the result set
* @throws Exception
*/
public void numberLines(int lineCount) throws Exception {

String METHOD_NAME = "numberLines()";

try {

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of the result set will be
* numbered 1, 2, 3, etc.
*/
lineCounter++;

/* Return the value of the line counter. */
set(1, lineCounter);
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("countRows() - " +
excp.getMessage());
}
}
/**
* Method numberRows() is used to number the rows of a result set.
*
* <p>This method accomplishes the same result as the numberLines()
method elsewhere
* in this class but uses the 'getScratchpad()' and 'setScratchpad()' methods
* instead of a class variable so that developers can make an informed comparison
* between the two approaches.</p>
*
* @return int the current number of rows in the result set
* @throws Exception
*/
public void numberRows(int lineCount) throws Exception {

String METHOD_NAME = "numberRows()";

try {
/* Initialize the scratchpad buffer. */
scratchpadBuffer = getScratchpad();

/* Read the contents of the DB2 scratchpad. */
ByteArrayInputStream byteArrayInputStream = new
ByteArrayInputStream(scratchpadBuffer);
DataInputStream dataInputStream = new
DataInputStream(byteArrayInputStream);

/* Write a byte stream containing the initial value of the row counter, which is 0. */
ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
DataOutputStream dataOutputStream = new
DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt(rowCounter);

/*
* Copy the byte stream to a byte array. Copy that byte array to *another* byte array.
* Set the DB2 scratchpad equal to the second byte array.
*/
byte[] byteArrayBuffer = byteArrayOutputStream.toByteArray(); for(int ix = 0; ix < byteArrayBuffer.length; ix++) {
scratchpadBuffer[ix] = byteArrayBuffer[ix];
}
setScratchpad(scratchpadBuffer);

/* Get the DB2 scratchpad and parse it to get the current value of the row counter. */
byte[] scratchpadBuffer = getScratchpad();
rowCounter = dataInputStream.readInt();

/*
* Increment the line counter. The counter starts at 0 and
increments once for each
* row in the result set of the query. Therefore, the lines of the result set will
* be numbered 1, 2, 3, etc.
*/
rowCounter++;

/* Return the value of the row counter. */
set(1, rowCounter);
} catch (IOException excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
} catch (Exception excp) {
excp.printStackTrace();
throw new IllegalArgumentException("numberRows() - " +
excp.getMessage());
}
}
}


--------------------------------------------------------------------------

--
---------------------

Nov 12 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

55
by: Elijah | last post by:
I have read many of the topics on learning C++ or Java first. It seems like everyone says something different. I would like to know if I should learn C++ or Java. First a little about myself. I...
8
by: Beatrice Rutger | last post by:
Hi, I am a previous Micro$oft desertee (moved from VB/VC++ to Java before this whole DOTNET thing) because I had several issues with Micro$oft. I am not completely in love with Windoze, but I...
1
by: David Van D | last post by:
Hi there, A few weeks until I begin my journey towards a degree in Computer Science at Canterbury University in New Zealand, Anyway the course tutors are going to be teaching us JAVA wth bluej...
20
by: mayershome | last post by:
Hi! I'dont have any experiences in programming... what language should I start learning???? C? C++ or Java`? greetz
0
by: Jobs | last post by:
Download the JAVA , .NET and SQL Server interview sheet and rate yourself. This will help you judge yourself are you really worth of attending interviews. If you own a company best way to judge if...
2
by: Jobs | last post by:
Download the JAVA , .NET and SQL Server interview with answers Download the JAVA , .NET and SQL Server interview sheet and rate yourself. This will help you judge yourself are you really worth of...
2
by: freepdfforjobs | last post by:
Full eBook with 4000 C#, JAVA,.NET and SQL Server Interview questions http://www.questpond.com/SampleInterviewQuestionBook.zip Download the JAVA , .NET and SQL Server interview sheet and rate...
1
by: saytri | last post by:
Hi i'm a student studying java (i'm still a beginner). i have a project were i have to do a quiz with a set of questions. So i think that i have to type the questions in a textfile for example in...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.